home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / Common / src / d3dsaver.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  121.8 KB  |  3,338 lines

  1. //-----------------------------------------------------------------------------
  2. // File: D3DSaver.cpp
  3. //
  4. // Desc: Framework for screensavers that use Direct3D 8.0.
  5. //
  6. // Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #include <Windows.h>
  9. #include <windowsx.h>
  10. #include <commctrl.h>
  11. #include <stdio.h>
  12. #include <tchar.h>
  13. #include <regstr.h>
  14. #define COMPILE_MULTIMON_STUBS
  15. #include <multimon.h>
  16. #include <mmsystem.h>
  17. #include <D3DX8.h>
  18. #include "D3DSaver.h"
  19. #include "dxutil.h"
  20.  
  21. // Resource IDs.  D3DSaver assumes that you will create resources with
  22. // these IDs that it can use.  The easiest way to do this is to copy
  23. // the resources from the rc file of an existing D3DSaver-based program.
  24. #define IDI_MAIN_ICON                   101
  25. #define IDD_SINGLEMONITORSETTINGS       200
  26. #define IDD_MULTIMONITORSETTINGS        201
  27.  
  28. #define IDC_MONITORSTAB                 2000
  29. #define IDC_TABNAMEFMT                  2001
  30. #define IDC_ADAPTERNAME                 2002
  31. #define IDC_RENDERING                   2003
  32. #define IDC_MOREINFO                    2004
  33. #define IDC_DISABLEHW                   2005
  34. #define IDC_SCREENUSAGEBOX              2006
  35. #define IDC_RENDER                      2007
  36. #define IDC_LEAVEBLACK                  2008
  37. #define IDC_DISPLAYMODEBOX              2009
  38. #define IDC_MODESSTATIC                 2010
  39. #define IDC_MODESCOMBO                  2011
  40. #define IDC_AUTOMATIC                   2012
  41. #define IDC_DISPLAYMODENOTE             2013
  42. #define IDC_GENERALBOX                  2014
  43. #define IDC_SAME                        2015
  44. #define IDC_MODEFMT                     2016
  45.  
  46. #define IDS_ERR_GENERIC                 2100
  47. #define IDS_ERR_NODIRECT3D              2101
  48. #define IDS_ERR_NOWINDOWEDHAL           2102
  49. #define IDS_ERR_CREATEDEVICEFAILED      2103
  50. #define IDS_ERR_NOCOMPATIBLEDEVICES     2104
  51. #define IDS_ERR_NOHARDWAREDEVICE        2105
  52. #define IDS_ERR_HALNOTCOMPATIBLE        2106
  53. #define IDS_ERR_NOHALTHISMODE           2107
  54. #define IDS_ERR_MEDIANOTFOUND           2108
  55. #define IDS_ERR_RESIZEFAILED            2109
  56. #define IDS_ERR_OUTOFMEMORY             2110
  57. #define IDS_ERR_OUTOFVIDEOMEMORY        2111
  58. #define IDS_ERR_NOPREVIEW               2112
  59.  
  60. #define IDS_INFO_GOODHAL                2200
  61. #define IDS_INFO_BADHAL_GOODSW          2201
  62. #define IDS_INFO_BADHAL_BADSW           2202
  63. #define IDS_INFO_BADHAL_NOSW            2203
  64. #define IDS_INFO_NOHAL_GOODSW           2204
  65. #define IDS_INFO_NOHAL_BADSW            2205
  66. #define IDS_INFO_NOHAL_NOSW             2206
  67. #define IDS_INFO_DISABLEDHAL_GOODSW     2207
  68. #define IDS_INFO_DISABLEDHAL_BADSW      2208
  69. #define IDS_INFO_DISABLEDHAL_NOSW       2209
  70. #define IDS_RENDERING_HAL               2210
  71. #define IDS_RENDERING_SW                2211
  72. #define IDS_RENDERING_NONE              2212
  73.  
  74.  
  75. // Use the following structure rather than DISPLAY_DEVICE, since some old 
  76. // versions of DISPLAY_DEVICE are missing the last two fields and this can
  77. // cause problems with EnumDisplayDevices on Windows 2000.
  78. struct DISPLAY_DEVICE_FULL
  79. {
  80.     DWORD  cb;
  81.     TCHAR  DeviceName[32];
  82.     TCHAR  DeviceString[128];
  83.     DWORD  StateFlags;
  84.     TCHAR  DeviceID[128];
  85.     TCHAR  DeviceKey[128];
  86. };
  87.  
  88.  
  89. static CD3DScreensaver* s_pD3DScreensaver = NULL;
  90.  
  91.  
  92. //-----------------------------------------------------------------------------
  93. // Name: CD3DScreensaver()
  94. // Desc: Constructor
  95. //-----------------------------------------------------------------------------
  96. CD3DScreensaver::CD3DScreensaver()
  97. {
  98.     s_pD3DScreensaver = this;
  99.  
  100.     m_bCheckingSaverPassword = FALSE;
  101.     m_bIs9x = FALSE;
  102.     m_dwSaverMouseMoveCount = 0;
  103.     m_hWndParent = NULL;
  104.     m_hPasswordDLL = NULL;
  105.     m_hWnd = NULL;
  106.     m_VerifySaverPassword = NULL;
  107.     
  108.     m_bAllScreensSame = FALSE;
  109.     m_pD3D = NULL;
  110.     m_pd3dDevice = NULL;
  111.     m_bWindowed = FALSE;
  112.     m_bWaitForInputIdle = FALSE;
  113.  
  114.     m_bErrorMode = FALSE;
  115.     m_hrError = S_OK;
  116.     m_szError[0] = TEXT('\0');
  117.  
  118.     m_fFPS              = 0.0f;
  119.     m_strDeviceStats[0] = TEXT('\0');
  120.     m_strFrameStats[0]  = TEXT('\0');
  121.  
  122.     // Note: clients should load a resource into m_strWindowTitle to localize this string
  123.     lstrcpy( m_strWindowTitle, TEXT("Screen Saver") );
  124.     m_bAllowRef = FALSE;
  125.     m_bUseDepthBuffer = FALSE;
  126.     m_bMultithreaded = FALSE;
  127.     m_bOneScreenOnly = FALSE;
  128.     m_strRegPath[0] = TEXT('\0');
  129.     m_dwMinDepthBits = 16;
  130.     m_dwMinStencilBits = 0;
  131.     m_SwapEffectFullscreen = D3DSWAPEFFECT_DISCARD;
  132.     m_SwapEffectWindowed = D3DSWAPEFFECT_COPY_VSYNC;
  133.  
  134.     SetRectEmpty( &m_rcRenderTotal );
  135.     SetRectEmpty( &m_rcRenderCurDevice );
  136.  
  137.     ZeroMemory( m_Monitors, sizeof(m_Monitors) );
  138.     m_dwNumMonitors = 0;
  139.  
  140.     ZeroMemory( m_Adapters, sizeof(m_Adapters) );
  141.     m_dwNumAdapters = 0;
  142.  
  143.     ZeroMemory( m_RenderUnits, sizeof(m_RenderUnits) );
  144.     m_dwNumRenderUnits = 0;
  145.  
  146.     m_fTime = 0.0f;
  147. }
  148.  
  149.  
  150.  
  151.  
  152. //-----------------------------------------------------------------------------
  153. // Name: Create()
  154. // Desc: Have the client program call this function before calling Run().
  155. //-----------------------------------------------------------------------------
  156. HRESULT CD3DScreensaver::Create( HINSTANCE hInstance )
  157. {
  158.     HRESULT hr;
  159.  
  160.     SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_IDLE );
  161.  
  162.     m_hInstance = hInstance;
  163.  
  164.     // Parse the command line and do the appropriate thing
  165.     TCHAR* pstrCmdLine = GetCommandLine();
  166.     m_SaverMode = ParseCommandLine( pstrCmdLine );
  167.  
  168.     EnumMonitors();
  169.  
  170.     // Create the screen saver window(s)
  171.     if( m_SaverMode == sm_preview || 
  172.         m_SaverMode == sm_test    || 
  173.         m_SaverMode == sm_full )
  174.     {
  175.         if( FAILED( hr = CreateSaverWindow() ) )
  176.         {
  177.             m_bErrorMode = TRUE;
  178.             m_hrError = hr;
  179.         }
  180.     }
  181.  
  182.     if( m_SaverMode == sm_preview )
  183.     {
  184.         // In preview mode, "pause" (enter a limited message loop) briefly 
  185.         // before proceeding, so the display control panel knows to update itself.
  186.         m_bWaitForInputIdle = TRUE;
  187.  
  188.         // Post a message to mark the end of the initial group of window messages
  189.         PostMessage( m_hWnd, WM_USER, 0, 0 );
  190.  
  191.         MSG msg;
  192.         while( m_bWaitForInputIdle )
  193.         {
  194.             // If GetMessage returns FALSE, it's quitting time.
  195.             if( !GetMessage( &msg, m_hWnd, 0, 0 ) )
  196.             {
  197.                 // Post the quit message to handle it later
  198.                 PostQuitMessage(0);
  199.                 break;
  200.             }
  201.  
  202.             TranslateMessage( &msg );
  203.             DispatchMessage( &msg );
  204.         }
  205.     }
  206.  
  207.     // Create Direct3D object
  208.     if( (m_pD3D = Direct3DCreate8( D3D_SDK_VERSION ) ) == NULL )
  209.     {
  210.         m_bErrorMode = TRUE;
  211.         m_hrError = D3DAPPERR_NODIRECT3D;
  212.         return S_OK;
  213.     }
  214.  
  215.     // Give the app the opportunity to register a pluggable SW D3D Device.
  216.     if( FAILED( hr = RegisterSoftwareDevice() ) )
  217.     {
  218.         m_bErrorMode = TRUE;
  219.         m_hrError = hr;
  220.         return S_OK;
  221.     }
  222.  
  223.     // Build a list of Direct3D adapters, modes and devices. The
  224.     // ConfirmDevice() callback is used to confirm that only devices that
  225.     // meet the app's requirements are considered.
  226.     if( FAILED( hr = BuildDeviceList() ) )
  227.     {
  228.         m_bErrorMode = TRUE;
  229.         m_hrError = hr;
  230.         return S_OK;
  231.     }
  232.  
  233.     // Make sure that at least one valid usable D3D device was found
  234.     BOOL bCompatibleDeviceFound = FALSE;
  235.     for( DWORD iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  236.     {
  237.         if( m_Adapters[iAdapter]->bHasAppCompatHAL || 
  238.             m_Adapters[iAdapter]->bHasAppCompatSW )
  239.         {
  240.             bCompatibleDeviceFound = TRUE;
  241.             break;
  242.         }
  243.     }
  244.     if( !bCompatibleDeviceFound )
  245.     {
  246.         m_bErrorMode = TRUE;
  247.         m_hrError = D3DAPPERR_NOCOMPATIBLEDEVICES;
  248.         return S_OK;
  249.     }
  250.  
  251.     // Read any settings we need
  252.     ReadSettings();
  253.  
  254.     return S_OK;
  255. }
  256.  
  257.  
  258.  
  259.  
  260. //-----------------------------------------------------------------------------
  261. // Name: EnumMonitors()
  262. // Desc: Determine HMONITOR, desktop rect, and other info for each monitor.  
  263. //       Note that EnumDisplayDevices enumerates monitors in the order 
  264. //       indicated on the Settings page of the Display control panel, which 
  265. //       is the order we want to list monitors in, as opposed to the order 
  266. //       used by D3D's GetAdapterInfo.
  267. //-----------------------------------------------------------------------------
  268. VOID CD3DScreensaver::EnumMonitors( VOID )
  269. {
  270.     DWORD iDevice = 0;
  271.     DISPLAY_DEVICE_FULL dispdev;
  272.     DISPLAY_DEVICE_FULL dispdev2;
  273.     DEVMODE devmode;
  274.     dispdev.cb = sizeof(dispdev);
  275.     dispdev2.cb = sizeof(dispdev2);
  276.     devmode.dmSize = sizeof(devmode);
  277.     devmode.dmDriverExtra = 0;
  278.     MonitorInfo* pMonitorInfoNew;
  279.     while( EnumDisplayDevices(NULL, iDevice, (DISPLAY_DEVICE*)&dispdev, 0) )
  280.     {
  281.         // Ignore NetMeeting's mirrored displays
  282.         if( (dispdev.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0 )
  283.         {
  284.             // To get monitor info for a display device, call EnumDisplayDevices
  285.             // a second time, passing dispdev.DeviceName (from the first call) as
  286.             // the first parameter.
  287.             EnumDisplayDevices(dispdev.DeviceName, 0, (DISPLAY_DEVICE*)&dispdev2, 0);
  288.  
  289.             pMonitorInfoNew = &m_Monitors[m_dwNumMonitors];
  290.             ZeroMemory( pMonitorInfoNew, sizeof(MonitorInfo) );
  291.             lstrcpy( pMonitorInfoNew->strDeviceName, dispdev.DeviceString );
  292.             lstrcpy( pMonitorInfoNew->strMonitorName, dispdev2.DeviceString );
  293.             pMonitorInfoNew->iAdapter = NO_ADAPTER;
  294.             
  295.             if( dispdev.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP )
  296.             {
  297.                 EnumDisplaySettings( dispdev.DeviceName, ENUM_CURRENT_SETTINGS, &devmode );
  298.                 if( dispdev.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE )
  299.                 {
  300.                     // For some reason devmode.dmPosition is not always (0, 0)
  301.                     // for the primary display, so force it.
  302.                     pMonitorInfoNew->rcScreen.left = 0;
  303.                     pMonitorInfoNew->rcScreen.top = 0;
  304.                 }
  305.                 else
  306.                 {
  307.                     pMonitorInfoNew->rcScreen.left = devmode.dmPosition.x;
  308.                     pMonitorInfoNew->rcScreen.top = devmode.dmPosition.y;
  309.                 }
  310.                 pMonitorInfoNew->rcScreen.right = pMonitorInfoNew->rcScreen.left + devmode.dmPelsWidth;
  311.                 pMonitorInfoNew->rcScreen.bottom = pMonitorInfoNew->rcScreen.top + devmode.dmPelsHeight;
  312.                 pMonitorInfoNew->hMonitor = MonitorFromRect( &pMonitorInfoNew->rcScreen, MONITOR_DEFAULTTONULL );
  313.             }
  314.             m_dwNumMonitors++;
  315.             if( m_dwNumMonitors == MAX_DISPLAYS )
  316.                 break;
  317.         }
  318.         iDevice++;
  319.     }
  320. }
  321.  
  322.  
  323.  
  324.  
  325. //-----------------------------------------------------------------------------
  326. // Name: Run()
  327. // Desc: Starts main execution of the screen saver.
  328. //-----------------------------------------------------------------------------
  329. INT CD3DScreensaver::Run()
  330. {
  331.     HRESULT hr;
  332.  
  333.     // Parse the command line and do the appropriate thing
  334.     switch ( m_SaverMode )
  335.     {
  336.         case sm_config:
  337.         {
  338.             if( m_bErrorMode )
  339.             {
  340.                 DisplayErrorMsg( m_hrError, 0 );
  341.             }
  342.             else
  343.             {
  344.                 DoConfig();
  345.             }
  346.             break;
  347.         }
  348.         
  349.         case sm_preview:
  350.         case sm_test:
  351.         case sm_full:
  352.         {
  353.             if( FAILED( hr = DoSaver() ) )
  354.                 DisplayErrorMsg( hr, 0 );
  355.             break;
  356.         }
  357.         
  358.         case sm_passwordchange:
  359.         {
  360.             ChangePassword();
  361.             break;
  362.         }
  363.     }
  364.  
  365.     for( DWORD iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  366.         SAFE_DELETE( m_Adapters[iAdapter] );
  367.     SAFE_RELEASE( m_pD3D );
  368.     return 0;
  369. }
  370.  
  371.  
  372.  
  373.  
  374. //-----------------------------------------------------------------------------
  375. // Name: ParseCommandLine()
  376. // Desc: Interpret command-line parameters passed to this app.
  377. //-----------------------------------------------------------------------------
  378. SaverMode CD3DScreensaver::ParseCommandLine( TCHAR* pstrCommandLine )
  379. {
  380.     m_hWndParent = NULL;
  381.  
  382.     // Skip the first part of the command line, which is the full path 
  383.     // to the exe.  If it contains spaces, it will be contained in quotes.
  384.     if (*pstrCommandLine == TEXT('\"'))
  385.     {
  386.         pstrCommandLine++;
  387.         while (*pstrCommandLine != TEXT('\0') && *pstrCommandLine != TEXT('\"'))
  388.             pstrCommandLine++;
  389.         if( *pstrCommandLine == TEXT('\"') )
  390.             pstrCommandLine++;
  391.     }
  392.     else
  393.     {
  394.         while (*pstrCommandLine != TEXT('\0') && *pstrCommandLine != TEXT(' '))
  395.             pstrCommandLine++;
  396.         if( *pstrCommandLine == TEXT(' ') )
  397.             pstrCommandLine++;
  398.     }
  399.  
  400.     // Skip along to the first option delimiter "/" or "-"
  401.     while ( *pstrCommandLine != TEXT('\0') && *pstrCommandLine != TEXT('/') && *pstrCommandLine != TEXT('-') )
  402.         pstrCommandLine++;
  403.  
  404.     // If there wasn't one, then must be config mode
  405.     if ( *pstrCommandLine == TEXT('\0') )
  406.         return sm_config;
  407.  
  408.     // Otherwise see what the option was
  409.     switch ( *(++pstrCommandLine) )
  410.     {
  411.         case 'c':
  412.         case 'C':
  413.             pstrCommandLine++;
  414.             while ( *pstrCommandLine && !isdigit(*pstrCommandLine) )
  415.                 pstrCommandLine++;
  416.             if ( isdigit(*pstrCommandLine) )
  417.             {
  418. #ifdef _WIN64
  419.                 CHAR strCommandLine[2048];
  420.                 DXUtil_ConvertGenericStringToAnsi(strCommandLine, pstrCommandLine, 2048);
  421.                 m_hWndParent = HWND(_atoi64(strCommandLine));
  422. #else
  423.                 m_hWndParent = HWND(_ttol(pstrCommandLine));
  424. #endif
  425.             }
  426.             else
  427.             {
  428.                 m_hWndParent = NULL;
  429.             }
  430.             return sm_config;
  431.  
  432.         case 't':
  433.         case 'T':
  434.             return sm_test;
  435.  
  436.         case 'p':
  437.         case 'P':
  438.             // Preview-mode, so option is followed by the parent HWND in decimal
  439.             pstrCommandLine++;
  440.             while ( *pstrCommandLine && !isdigit(*pstrCommandLine) )
  441.                 pstrCommandLine++;
  442.             if ( isdigit(*pstrCommandLine) )
  443.             {
  444. #ifdef _WIN64
  445.                 CHAR strCommandLine[2048];
  446.                 DXUtil_ConvertGenericStringToAnsi(strCommandLine, pstrCommandLine, 2048);
  447.                 m_hWndParent = HWND(_atoi64(strCommandLine));
  448. #else
  449.                 m_hWndParent = HWND(_ttol(pstrCommandLine));
  450. #endif
  451.             }
  452.             return sm_preview;
  453.  
  454.         case 'a':
  455.         case 'A':
  456.             // Password change mode, so option is followed by parent HWND in decimal
  457.             pstrCommandLine++;
  458.             while ( *pstrCommandLine && !isdigit(*pstrCommandLine) )
  459.                 pstrCommandLine++;
  460.             if ( isdigit(*pstrCommandLine) )
  461.             {
  462. #ifdef _WIN64
  463.                 CHAR strCommandLine[2048];
  464.                 DXUtil_ConvertGenericStringToAnsi(strCommandLine, pstrCommandLine, 2048);
  465.                 m_hWndParent = HWND(_atoi64(strCommandLine));
  466. #else
  467.                 m_hWndParent = HWND(_ttol(pstrCommandLine));
  468. #endif
  469.             }
  470.             return sm_passwordchange;
  471.  
  472.         default:
  473.             // All other options => run the screensaver (typically this is "/s")
  474.             return sm_full;
  475.     }
  476. }
  477.  
  478.  
  479.  
  480.  
  481. //-----------------------------------------------------------------------------
  482. // Name: CreateSaverWindow
  483. // Desc: Register and create the appropriate window(s)
  484. //-----------------------------------------------------------------------------
  485. HRESULT CD3DScreensaver::CreateSaverWindow()
  486. {
  487. /*
  488.     // Uncomment this code to allow stepping thru code in the preview case
  489.     if( m_SaverMode == sm_preview )
  490.     {
  491.         WNDCLASS cls;
  492.         cls.hCursor        = NULL; 
  493.         cls.hIcon          = NULL; 
  494.         cls.lpszMenuName   = NULL;
  495.         cls.lpszClassName  = TEXT("Parent"); 
  496.         cls.hbrBackground  = (HBRUSH) GetStockObject(WHITE_BRUSH);
  497.         cls.hInstance      = m_hInstance; 
  498.         cls.style          = CS_VREDRAW|CS_HREDRAW|CS_SAVEBITS|CS_DBLCLKS;
  499.         cls.lpfnWndProc    = DefWindowProc;
  500.         cls.cbWndExtra     = 0; 
  501.         cls.cbClsExtra     = 0; 
  502.         RegisterClass( &cls );
  503.  
  504.         // Create the window
  505.         RECT rect;
  506.         HWND hwnd;
  507.         rect.left = rect.top = 40;
  508.         rect.right = rect.left+200;
  509.         rect.bottom = rect.top+200;
  510.         AdjustWindowRect( &rect, WS_VISIBLE|WS_OVERLAPPED|WS_CAPTION|WS_POPUP, FALSE );
  511.         hwnd = CreateWindow( TEXT("Parent"), TEXT("FakeShell"),
  512.             WS_VISIBLE|WS_OVERLAPPED|WS_CAPTION|WS_POPUP, rect.left, rect.top,
  513.             rect.right-rect.left, rect.bottom-rect.top, NULL,
  514.             NULL, m_hInstance, NULL );
  515.         m_hWndParent = hwnd;
  516.     }
  517. */
  518.     
  519.     // Register an appropriate window class
  520.     WNDCLASS    cls;
  521.     cls.hCursor        = LoadCursor( NULL, IDC_ARROW );
  522.     cls.hIcon          = LoadIcon( m_hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) ); 
  523.     cls.lpszMenuName   = NULL;
  524.     cls.lpszClassName  = TEXT("D3DSaverWndClass");
  525.     cls.hbrBackground  = (HBRUSH) GetStockObject(BLACK_BRUSH);
  526.     cls.hInstance      = m_hInstance; 
  527.     cls.style          = CS_VREDRAW|CS_HREDRAW;
  528.     cls.lpfnWndProc    = SaverProcStub;
  529.     cls.cbWndExtra     = 0; 
  530.     cls.cbClsExtra     = 0; 
  531.     RegisterClass( &cls );
  532.  
  533.     // Create the window
  534.     RECT rc;
  535.     DWORD dwStyle;
  536.     switch ( m_SaverMode )
  537.     {
  538.         case sm_preview:
  539.             GetClientRect( m_hWndParent, &rc );
  540.             dwStyle = WS_VISIBLE | WS_CHILD;
  541.             AdjustWindowRect( &rc, dwStyle, FALSE );
  542.             m_hWnd = CreateWindow( TEXT("D3DSaverWndClass"), m_strWindowTitle, dwStyle, 
  543.                                     rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, 
  544.                                     m_hWndParent, NULL, m_hInstance, this );
  545.             m_Monitors[0].hWnd = m_hWnd;
  546.             GetClientRect( m_hWnd, &m_rcRenderTotal );
  547.             GetClientRect( m_hWnd, &m_rcRenderCurDevice );
  548.             break;
  549.  
  550.         case sm_test:
  551.             rc.left = rc.top = 50;
  552.             rc.right = rc.left+600;
  553.             rc.bottom = rc.top+400;
  554.             dwStyle = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
  555.             AdjustWindowRect( &rc, dwStyle, FALSE );
  556.             m_hWnd = CreateWindow( TEXT("D3DSaverWndClass"), m_strWindowTitle, dwStyle, 
  557.                                    rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, 
  558.                                    NULL, NULL, m_hInstance, this );
  559.             m_Monitors[0].hWnd = m_hWnd;
  560.             GetClientRect( m_hWnd, &m_rcRenderTotal );
  561.             GetClientRect( m_hWnd, &m_rcRenderCurDevice );
  562.             break;
  563.  
  564.         case sm_full:
  565.             // Create windows for each monitor.  Note that m_hWnd is NULL when CreateWindowEx
  566.             // is called for the first monitor, so that window has no parent.  Windows for
  567.             // additional monitors are created as children of the window for the first monitor.
  568.             dwStyle = WS_VISIBLE | WS_POPUP;
  569.             m_hWnd = NULL;
  570.             for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  571.             {
  572.                 MonitorInfo* pMonitorInfo;
  573.                 pMonitorInfo = &m_Monitors[iMonitor];
  574.                 if( pMonitorInfo->hMonitor == NULL )
  575.                     continue;
  576.                 rc = pMonitorInfo->rcScreen;
  577.                 pMonitorInfo->hWnd = CreateWindowEx( WS_EX_TOPMOST, TEXT("D3DSaverWndClass"), 
  578.                     m_strWindowTitle, dwStyle, rc.left, rc.top, rc.right - rc.left, 
  579.                     rc.bottom - rc.top, m_hWnd, NULL, m_hInstance, this );
  580.                 if( pMonitorInfo->hWnd == NULL )
  581.                     return E_FAIL;
  582.                 if( m_hWnd == NULL )
  583.                     m_hWnd = pMonitorInfo->hWnd;
  584.             }
  585.     }
  586.     if ( m_hWnd == NULL )
  587.         return E_FAIL;
  588.  
  589.     return S_OK;
  590. }
  591.  
  592.  
  593.  
  594. //-----------------------------------------------------------------------------
  595. // Name: DoSaver()
  596. // Desc: Run the screensaver graphics - may be preview, test or full-on mode
  597. //-----------------------------------------------------------------------------
  598. HRESULT CD3DScreensaver::DoSaver()
  599. {
  600.     HRESULT hr;
  601.  
  602.     // Figure out if we're on Win9x
  603.     OSVERSIONINFO osvi; 
  604.     osvi.dwOSVersionInfoSize = sizeof(osvi);
  605.     GetVersionEx( &osvi );
  606.     m_bIs9x = (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
  607.  
  608.     // If we're in full on mode, and on 9x, then need to load the password DLL
  609.     if ( m_SaverMode == sm_full && m_bIs9x )
  610.     {
  611.         // Only do this if the password is set - check registry:
  612.         HKEY hKey; 
  613.         if ( RegOpenKey( HKEY_CURRENT_USER , REGSTR_PATH_SCREENSAVE , &hKey ) == ERROR_SUCCESS ) 
  614.         { 
  615.             DWORD dwVal;
  616.             DWORD dwSize = sizeof(dwVal); 
  617.  
  618.             if ( (RegQueryValueEx( hKey, REGSTR_VALUE_USESCRPASSWORD, NULL, NULL,
  619.                                    (BYTE *)&dwVal, &dwSize ) == ERROR_SUCCESS) && dwVal ) 
  620.             { 
  621.                 m_hPasswordDLL = LoadLibrary( TEXT("PASSWORD.CPL") );
  622.                 if ( m_hPasswordDLL )
  623.                     m_VerifySaverPassword = (VERIFYPWDPROC)GetProcAddress( m_hPasswordDLL, "VerifyScreenSavePwd" );
  624.                 RegCloseKey( hKey );
  625.             }
  626.         }
  627.     }
  628.  
  629.     // Initialize the application timer
  630.     DXUtil_Timer( TIMER_START );
  631.  
  632.     if( !m_bErrorMode )
  633.     {
  634.         // Initialize the app's custom scene stuff
  635.         if( FAILED( hr = OneTimeSceneInit() ) )
  636.             return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  637.  
  638.         // Do graphical init stuff
  639.         if ( FAILED(hr = Initialize3DEnvironment()) )
  640.             return hr;
  641.     }
  642.  
  643.     // Flag as screensaver running if in full on mode
  644.     if ( m_SaverMode == sm_full )
  645.     {
  646.         BOOL bUnused;
  647.         SystemParametersInfo( SPI_SCREENSAVERRUNNING, TRUE, &bUnused, 0 );
  648.     }
  649.  
  650.     // Message pump
  651.     BOOL bGotMsg;
  652.     MSG msg;
  653.     msg.message = WM_NULL;
  654.     while ( msg.message != WM_QUIT )
  655.     {
  656.         bGotMsg = PeekMessage( &msg, NULL, 0, 0, PM_REMOVE );
  657.         if( bGotMsg )
  658.         {
  659.             TranslateMessage( &msg );
  660.             DispatchMessage( &msg );
  661.         }
  662.         else
  663.         {
  664.             Sleep(10);
  665.             if( m_bErrorMode )
  666.             {
  667.                 UpdateErrorBox();
  668.             }
  669.             else
  670.             {
  671.                 Render3DEnvironment();
  672.             }
  673.         }
  674.     }
  675.  
  676.     return S_OK;
  677. }
  678.  
  679.  
  680.  
  681.  
  682. //-----------------------------------------------------------------------------
  683. // Name: ShutdownSaver()
  684. // Desc: 
  685. //-----------------------------------------------------------------------------
  686. VOID CD3DScreensaver::ShutdownSaver()
  687. {
  688.     // Unflag screensaver running if in full on mode
  689.     if ( m_SaverMode == sm_full )
  690.     {
  691.         BOOL bUnused;
  692.         SystemParametersInfo( SPI_SCREENSAVERRUNNING, FALSE, &bUnused, 0 );
  693.     }
  694.  
  695.     // Kill graphical stuff
  696.     Cleanup3DEnvironment();
  697.  
  698.     // Let client app clean up its resources
  699.     FinalCleanup();
  700.  
  701.     // Unload the password DLL (if we loaded it)
  702.     if ( m_hPasswordDLL != NULL )
  703.     {
  704.         FreeLibrary( m_hPasswordDLL );
  705.         m_hPasswordDLL = NULL;
  706.     }
  707.  
  708.     // Post message to drop out of message loop
  709.     PostQuitMessage( 0 );
  710. }
  711.  
  712.  
  713.  
  714.  
  715. //-----------------------------------------------------------------------------
  716. // Name: SaverProcStub()
  717. // Desc: This function forwards all window messages to SaverProc, which has
  718. //       access to the "this" pointer.
  719. //-----------------------------------------------------------------------------
  720. LRESULT CALLBACK CD3DScreensaver::SaverProcStub( HWND hWnd, UINT uMsg,
  721.                                                  WPARAM wParam, LPARAM lParam )
  722. {
  723.     return s_pD3DScreensaver->SaverProc( hWnd, uMsg, wParam, lParam );
  724. }
  725.  
  726.  
  727.  
  728.  
  729. //-----------------------------------------------------------------------------
  730. // Name: SaverProc()
  731. // Desc: Handle window messages for main screensaver windows (one per screen).
  732. //-----------------------------------------------------------------------------
  733. LRESULT CD3DScreensaver::SaverProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  734. {
  735.     switch ( uMsg )
  736.         {
  737.         case WM_USER:
  738.             // All initialization messages have gone through.  Allow
  739.             // 500ms of idle time, then proceed with initialization.
  740.             SetTimer( hWnd, 1, 500, NULL );
  741.             break;
  742.  
  743.         case WM_TIMER:
  744.             // Initial idle time is done, proceed with initialization.
  745.             m_bWaitForInputIdle = FALSE;
  746.             KillTimer( hWnd, 1 );
  747.             break;
  748.  
  749.         case WM_DESTROY:
  750.             if( m_SaverMode == sm_preview || m_SaverMode == sm_test )
  751.                 ShutdownSaver();
  752.             break;
  753.  
  754.         case WM_SETCURSOR:
  755.             if ( m_SaverMode == sm_full && !m_bCheckingSaverPassword )
  756.             {
  757.                 // Hide cursor
  758.                 SetCursor( NULL );
  759.                 return TRUE;
  760.             }
  761.             break;
  762.  
  763.         case WM_PAINT:
  764.         {
  765.             // Show error message, if there is one
  766.             PAINTSTRUCT ps;
  767.             BeginPaint( hWnd, &ps );
  768.  
  769.             // In preview mode, just fill 
  770.             // the preview window with black. 
  771.             if( !m_bErrorMode && m_SaverMode == sm_preview )
  772.             {
  773.                 RECT rc;
  774.                 GetClientRect(hWnd,&rc);
  775.                 FillRect(ps.hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH) );
  776.             }
  777.             else
  778.             {
  779.                 DoPaint( hWnd, ps.hdc );
  780.             }
  781.  
  782.             EndPaint( hWnd, &ps );
  783.             return 0;
  784.         }
  785.  
  786.         case WM_ERASEBKGND:
  787.             // Erase background if checking password or if window is not
  788.             // assigned to a render unit
  789.             if( !m_bCheckingSaverPassword )
  790.             {
  791.                 RenderUnit* pRenderUnit;
  792.                 D3DAdapterInfo* pD3DAdapterInfo;
  793.                 for( DWORD iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  794.                 {
  795.                     pRenderUnit = &m_RenderUnits[iRenderUnit];
  796.                     pD3DAdapterInfo = m_Adapters[pRenderUnit->iAdapter];
  797.                     if( pD3DAdapterInfo->hWndDevice == hWnd )
  798.                         return TRUE; // don't erase this window
  799.                 }
  800.             }
  801.             break;
  802.  
  803.         case WM_MOUSEMOVE:
  804.             if( m_SaverMode != sm_test )
  805.             {
  806.                 static INT xPrev = -1;
  807.                 static INT yPrev = -1;
  808.                 INT xCur = GET_X_LPARAM(lParam);
  809.                 INT yCur = GET_Y_LPARAM(lParam);
  810.                 if( xCur != xPrev || yCur != yPrev )
  811.                 {
  812.                     xPrev = xCur;
  813.                     yPrev = yCur;
  814.                     m_dwSaverMouseMoveCount++;
  815.                     if ( m_dwSaverMouseMoveCount > 5 )
  816.                         InterruptSaver();
  817.                 }
  818.             }
  819.             break;
  820.  
  821.         case WM_KEYDOWN:
  822.         case WM_LBUTTONDOWN:
  823.         case WM_RBUTTONDOWN:
  824.         case WM_MBUTTONDOWN:
  825.             if( m_SaverMode != sm_test )
  826.                 InterruptSaver();
  827.             break;
  828.  
  829.         case WM_ACTIVATEAPP:
  830.             if( wParam == FALSE && m_SaverMode != sm_test )
  831.                 InterruptSaver();
  832.             break;
  833.  
  834.         case WM_POWERBROADCAST:
  835.             if( wParam == PBT_APMSUSPEND && m_VerifySaverPassword == NULL )
  836.                 InterruptSaver();
  837.             break;
  838.  
  839.         case WM_SYSCOMMAND: 
  840.             if ( m_SaverMode == sm_full )
  841.             {
  842.                 switch ( wParam )
  843.                 {
  844.                     case SC_NEXTWINDOW:
  845.                     case SC_PREVWINDOW:
  846.                     case SC_SCREENSAVE:
  847.                     case SC_CLOSE:
  848.                         return FALSE;
  849.                 };
  850.             }
  851.             break;
  852.     }
  853.  
  854.     return DefWindowProc( hWnd, uMsg, wParam, lParam );
  855. }
  856.  
  857.  
  858.  
  859.  
  860. //-----------------------------------------------------------------------------
  861. // Name: InterruptSaver()
  862. // Desc: A message was received (mouse move, keydown, etc.) that may mean
  863. //       the screen saver should show the password dialog and/or shut down.
  864. //-----------------------------------------------------------------------------
  865. VOID CD3DScreensaver::InterruptSaver()
  866. {
  867.     HRESULT hr;
  868.     DWORD iRenderUnit;
  869.     RenderUnit* pRenderUnit;
  870.     BOOL bPasswordOkay = FALSE;
  871.  
  872.     if( m_SaverMode == sm_test ||
  873.         m_SaverMode == sm_full && !m_bCheckingSaverPassword )
  874.     {
  875.         if( m_bIs9x && m_SaverMode == sm_full )
  876.         {
  877.             // If no VerifyPassword function, then no password is set 
  878.             // or we're not on 9x. 
  879.             if ( m_VerifySaverPassword != NULL )
  880.             {
  881.                 // Shut down all D3D devices so we can show a Windows dialog
  882.                 for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  883.                 {
  884.                     pRenderUnit = &m_RenderUnits[iRenderUnit];
  885.                     SwitchToRenderUnit(iRenderUnit);
  886.                     if( pRenderUnit->bDeviceObjectsRestored )
  887.                     {
  888.                         InvalidateDeviceObjects();
  889.                         pRenderUnit->bDeviceObjectsRestored = FALSE;
  890.                     }
  891.                     if( pRenderUnit->bDeviceObjectsInited )
  892.                     {
  893.                         DeleteDeviceObjects();
  894.                         pRenderUnit->bDeviceObjectsInited = FALSE;
  895.                     }
  896.                     SAFE_RELEASE(pRenderUnit->pd3dDevice);
  897.                 }
  898.  
  899.                 // Make sure all adapter windows cover the whole screen,
  900.                 // even after deleting D3D devices (which may have caused
  901.                 // mode changes)
  902.                 D3DAdapterInfo* pD3DAdapterInfo;
  903.                 for( DWORD iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  904.                 {
  905.                     pD3DAdapterInfo = m_Adapters[iAdapter];
  906.                     ShowWindow( pD3DAdapterInfo->hWndDevice, SW_RESTORE );
  907.                     ShowWindow( pD3DAdapterInfo->hWndDevice, SW_MAXIMIZE );
  908.                 }
  909.  
  910.                 m_bCheckingSaverPassword = TRUE;
  911.  
  912.                 bPasswordOkay = m_VerifySaverPassword( m_hWnd );
  913.  
  914.                 m_bCheckingSaverPassword = FALSE;
  915.  
  916.                 if ( bPasswordOkay )
  917.                 {
  918.                     // D3D devices are all torn down, so it's safe
  919.                     // to discard all render units now (so we don't
  920.                     // try to clean them up again later).
  921.                     m_dwNumRenderUnits = 0;
  922.                 }
  923.                 else
  924.                 {
  925.                     // Back to screen saving...
  926.                     SetCursor( NULL );
  927.                     m_dwSaverMouseMoveCount = 0;
  928.  
  929.                     // Recreate all D3D devices
  930.                     for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  931.                     {
  932.                         pRenderUnit = &m_RenderUnits[iRenderUnit];
  933.                         hr = m_pD3D->CreateDevice(pRenderUnit->iAdapter, 
  934.                             pRenderUnit->DeviceType, m_hWnd, 
  935.                             pRenderUnit->dwBehavior, &pRenderUnit->d3dpp, 
  936.                             &pRenderUnit->pd3dDevice );
  937.                         if( FAILED( hr ) )
  938.                         {
  939.                             m_bErrorMode = TRUE;
  940.                             m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
  941.                         }
  942.                         else
  943.                         {
  944.                             SwitchToRenderUnit(iRenderUnit);
  945.                             if( FAILED(hr = InitDeviceObjects() ) )
  946.                             {
  947.                                 m_bErrorMode = TRUE;
  948.                                 m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
  949.                             }
  950.                             else 
  951.                             {
  952.                                 pRenderUnit->bDeviceObjectsInited = TRUE;
  953.                                 if( FAILED(hr = RestoreDeviceObjects() ) )
  954.                                 {
  955.                                     m_bErrorMode = TRUE;
  956.                                     m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
  957.                                 }
  958.                                 else
  959.                                 {
  960.                                     pRenderUnit->bDeviceObjectsRestored = TRUE;
  961.                                 }
  962.                             }
  963.                         }
  964.                     }
  965.  
  966.                     return;
  967.                 }
  968.             }
  969.         }
  970.         ShutdownSaver();
  971.     }
  972. }
  973.  
  974.  
  975.  
  976.  
  977. //-----------------------------------------------------------------------------
  978. // Name: Initialize3DEnvironment()
  979. // Desc: Set up D3D device(s)
  980. //-----------------------------------------------------------------------------
  981. HRESULT CD3DScreensaver::Initialize3DEnvironment()
  982. {
  983.     HRESULT hr;
  984.     DWORD iAdapter;
  985.     DWORD iMonitor;
  986.     D3DAdapterInfo* pD3DAdapterInfo;
  987.     MonitorInfo* pMonitorInfo;
  988.     DWORD iRenderUnit;
  989.     RenderUnit* pRenderUnit;
  990.     MONITORINFO monitorInfo;
  991.  
  992.     if ( m_SaverMode == sm_full )
  993.     {
  994.         // Fullscreen mode.  Create a RenderUnit for each monitor (unless 
  995.         // the user wants it black)
  996.         m_bWindowed = FALSE;
  997.  
  998.         if( m_bOneScreenOnly )
  999.         {
  1000.             // Set things up to only create a RenderUnit on the best device
  1001.             for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  1002.             {
  1003.                 pD3DAdapterInfo = m_Adapters[iAdapter];
  1004.                 pD3DAdapterInfo->bLeaveBlack = TRUE;
  1005.             }
  1006.             GetBestAdapter( &iAdapter );
  1007.             if( iAdapter == NO_ADAPTER )
  1008.             {
  1009.                 m_bErrorMode = TRUE;
  1010.                 m_hrError = D3DAPPERR_NOCOMPATIBLEDEVICES;
  1011.             }
  1012.             else
  1013.             {
  1014.                 pD3DAdapterInfo = m_Adapters[iAdapter];
  1015.                 pD3DAdapterInfo->bLeaveBlack = FALSE;
  1016.             }
  1017.         }
  1018.  
  1019.         for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  1020.         {
  1021.             pMonitorInfo = &m_Monitors[iMonitor];
  1022.             iAdapter = pMonitorInfo->iAdapter;
  1023.             if( iAdapter == NO_ADAPTER )
  1024.                 continue; 
  1025.             pD3DAdapterInfo = m_Adapters[iAdapter];
  1026.             if( pD3DAdapterInfo->bDisableHW && !pD3DAdapterInfo->bHasAppCompatSW &&
  1027.                 !m_bAllowRef )
  1028.             {
  1029.                 pD3DAdapterInfo->bLeaveBlack = TRUE;
  1030.             }
  1031.             if( !pD3DAdapterInfo->bLeaveBlack && pD3DAdapterInfo->dwNumDevices > 0 )
  1032.             {
  1033.                 pD3DAdapterInfo->hWndDevice = pMonitorInfo->hWnd;
  1034.                 pRenderUnit = &m_RenderUnits[m_dwNumRenderUnits++];
  1035.                 ZeroMemory( pRenderUnit, sizeof(RenderUnit) );
  1036.                 pRenderUnit->iAdapter = iAdapter;
  1037.                 if( FAILED( hr = CreateFullscreenRenderUnit( pRenderUnit ) ) )
  1038.                 {
  1039.                     // skip this render unit and leave screen blank
  1040.                     m_dwNumRenderUnits--;
  1041.                     m_bErrorMode = TRUE;
  1042.                     m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
  1043.                 }
  1044.             }
  1045.         }
  1046.     }
  1047.     else 
  1048.     {
  1049.         // Windowed mode, for test mode or preview window.  Just need one RenderUnit.
  1050.         m_bWindowed = TRUE;
  1051.  
  1052.         GetClientRect( m_hWnd, &m_rcRenderTotal );
  1053.         GetClientRect( m_hWnd, &m_rcRenderCurDevice );
  1054.  
  1055.         GetBestAdapter( &iAdapter );
  1056.         if( iAdapter == NO_ADAPTER )
  1057.         {
  1058.             m_bErrorMode = TRUE;
  1059.             m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
  1060.         }
  1061.         else
  1062.         {
  1063.             pD3DAdapterInfo = m_Adapters[iAdapter];
  1064.             pD3DAdapterInfo->hWndDevice = m_hWnd;
  1065.         }
  1066.         if( !m_bErrorMode )
  1067.         {
  1068.             pRenderUnit = &m_RenderUnits[m_dwNumRenderUnits++];
  1069.             ZeroMemory( pRenderUnit, sizeof(RenderUnit) );
  1070.             pRenderUnit->iAdapter = iAdapter;
  1071.             if( FAILED( hr = CreateWindowedRenderUnit( pRenderUnit ) ) )
  1072.             {
  1073.                 m_dwNumRenderUnits--;
  1074.                 m_bErrorMode = TRUE;
  1075.                 if( m_SaverMode == sm_preview )
  1076.                     m_hrError = D3DAPPERR_NOPREVIEW;
  1077.                 else
  1078.                     m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
  1079.             }
  1080.         }
  1081.     }
  1082.  
  1083.     // Once all mode changes are done, (re-)determine coordinates of all 
  1084.     // screens, and make sure windows still cover each screen
  1085.     for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  1086.     {
  1087.         pMonitorInfo = &m_Monitors[iMonitor];
  1088.         monitorInfo.cbSize = sizeof(MONITORINFO);
  1089.         GetMonitorInfo( pMonitorInfo->hMonitor, &monitorInfo );
  1090.         pMonitorInfo->rcScreen = monitorInfo.rcMonitor;
  1091.         if( !m_bWindowed )
  1092.         {
  1093.             SetWindowPos( pMonitorInfo->hWnd, HWND_TOPMOST, monitorInfo.rcMonitor.left, 
  1094.                 monitorInfo.rcMonitor.top, monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left, 
  1095.                 monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top, SWP_NOACTIVATE );
  1096.         }
  1097.     }
  1098.  
  1099.     // For fullscreen, determine bounds of the virtual screen containing all 
  1100.     // screens that are rendering.  Don't just use SM_XVIRTUALSCREEN, because 
  1101.     // we don't want to count screens that are just black
  1102.     if( !m_bWindowed )
  1103.     {
  1104.         for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  1105.         {
  1106.             pRenderUnit = &m_RenderUnits[iRenderUnit];
  1107.             pMonitorInfo = &m_Monitors[pRenderUnit->iMonitor];
  1108.             UnionRect( &m_rcRenderTotal, &m_rcRenderTotal, &pMonitorInfo->rcScreen );
  1109.         }
  1110.     }
  1111.  
  1112.     if( !m_bErrorMode )
  1113.     {
  1114.         // Initialize D3D devices for all render units
  1115.         for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  1116.         {
  1117.             pRenderUnit = &m_RenderUnits[iRenderUnit];
  1118.             SwitchToRenderUnit( iRenderUnit );
  1119.             if ( FAILED(hr = InitDeviceObjects() ) )
  1120.             {
  1121.                 m_bErrorMode = TRUE;
  1122.                 m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
  1123.             }
  1124.             else 
  1125.             {
  1126.                 pRenderUnit->bDeviceObjectsInited = TRUE;
  1127.                 if ( FAILED(hr = RestoreDeviceObjects() ) )
  1128.                 {
  1129.                     m_bErrorMode = TRUE;
  1130.                     m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
  1131.                 }
  1132.                 else
  1133.                 {
  1134.                     pRenderUnit->bDeviceObjectsRestored = TRUE;
  1135.                 }
  1136.             }
  1137.         }
  1138.         UpdateDeviceStats(); 
  1139.     }
  1140.  
  1141.     // Make sure all those display changes don't count as user mouse moves
  1142.     m_dwSaverMouseMoveCount = 0;
  1143.  
  1144.     return S_OK;
  1145. }
  1146.  
  1147.  
  1148.  
  1149.  
  1150. //-----------------------------------------------------------------------------
  1151. // Name: GetBestAdapter()
  1152. // Desc: To decide which adapter to use, loop through monitors until you find
  1153. //       one whose adapter has a compatible HAL.  If none, use the first 
  1154. //       monitor that has an compatible SW device.
  1155. //-----------------------------------------------------------------------------
  1156. BOOL CD3DScreensaver::GetBestAdapter( DWORD* piAdapter )
  1157. {
  1158.     DWORD iAdapterBest = NO_ADAPTER;
  1159.     DWORD iAdapter;
  1160.     DWORD iMonitor;
  1161.     MonitorInfo* pMonitorInfo;
  1162.     D3DAdapterInfo* pD3DAdapterInfo;
  1163.  
  1164.     for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  1165.     {
  1166.         pMonitorInfo = &m_Monitors[iMonitor];
  1167.         iAdapter = pMonitorInfo->iAdapter;
  1168.         if( iAdapter == NO_ADAPTER )
  1169.             continue; 
  1170.         pD3DAdapterInfo = m_Adapters[iAdapter];
  1171.         if( pD3DAdapterInfo->bHasAppCompatHAL )
  1172.         {
  1173.             iAdapterBest = iAdapter;
  1174.             break;
  1175.         }
  1176.         if( pD3DAdapterInfo->bHasAppCompatSW )
  1177.         {
  1178.             iAdapterBest = iAdapter;
  1179.             // but keep looking...
  1180.         }
  1181.     }
  1182.     *piAdapter = iAdapterBest;
  1183.  
  1184.     return (iAdapterBest != NO_ADAPTER);
  1185. }
  1186.  
  1187.  
  1188.  
  1189.  
  1190. //-----------------------------------------------------------------------------
  1191. // Name: CreateFullscreenRenderUnit()
  1192. // Desc: 
  1193. //-----------------------------------------------------------------------------
  1194. HRESULT CD3DScreensaver::CreateFullscreenRenderUnit( RenderUnit* pRenderUnit )
  1195. {
  1196.     HRESULT hr;
  1197.     UINT iAdapter = pRenderUnit->iAdapter;
  1198.     D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
  1199.     DWORD iMonitor = pD3DAdapterInfo->iMonitor;
  1200.     D3DDeviceInfo* pD3DDeviceInfo;
  1201.     D3DModeInfo* pD3DModeInfo;
  1202.     DWORD dwCurrentDevice;
  1203.     D3DDEVTYPE curType;
  1204.  
  1205.     if( iAdapter >= m_dwNumAdapters )
  1206.         return E_FAIL;
  1207.  
  1208.     if( pD3DAdapterInfo->dwNumDevices == 0 )
  1209.         return E_FAIL;
  1210.  
  1211.     // Find the best device for the adapter.  Use HAL
  1212.     // if it's there, otherwise SW, otherwise REF.
  1213.     dwCurrentDevice = 0xffff;
  1214.     curType = D3DDEVTYPE_FORCE_DWORD;
  1215.     for( DWORD iDevice = 0; iDevice < pD3DAdapterInfo->dwNumDevices; iDevice++)
  1216.     {
  1217.         pD3DDeviceInfo = &pD3DAdapterInfo->devices[iDevice];
  1218.         if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_HAL && !pD3DAdapterInfo->bDisableHW )
  1219.         {
  1220.             dwCurrentDevice = iDevice;
  1221.             curType = D3DDEVTYPE_HAL;
  1222.             break; // stop looking
  1223.         }
  1224.         else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_SW )
  1225.         {
  1226.             dwCurrentDevice = iDevice;
  1227.             curType = D3DDEVTYPE_SW;
  1228.             // but keep looking
  1229.         }
  1230.         else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_REF && m_bAllowRef && curType != D3DDEVTYPE_SW )
  1231.         {
  1232.             dwCurrentDevice = iDevice;
  1233.             curType = D3DDEVTYPE_REF;
  1234.             // but keep looking
  1235.         }
  1236.     }
  1237.     if( dwCurrentDevice == 0xffff )
  1238.         return D3DAPPERR_NOHARDWAREDEVICE;
  1239.     pD3DDeviceInfo = &pD3DAdapterInfo->devices[dwCurrentDevice];
  1240.  
  1241.     pD3DDeviceInfo->dwCurrentMode = 0xffff;
  1242.     if( pD3DAdapterInfo->dwUserPrefWidth != 0 )
  1243.     {
  1244.         // Try to find mode that matches user preference
  1245.         for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
  1246.         {
  1247.             pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  1248.             if( pD3DModeInfo->Width == pD3DAdapterInfo->dwUserPrefWidth &&
  1249.                 pD3DModeInfo->Height == pD3DAdapterInfo->dwUserPrefHeight &&
  1250.                 pD3DModeInfo->Format == pD3DAdapterInfo->d3dfmtUserPrefFormat )
  1251.             {
  1252.                 pD3DDeviceInfo->dwCurrentMode = iMode;
  1253.                 break;
  1254.             }
  1255.         }
  1256.     }
  1257.  
  1258.     // If user-preferred mode is not specified or not found,
  1259.     // use "Automatic" technique: 
  1260.     if( pD3DDeviceInfo->dwCurrentMode == 0xffff )
  1261.     {
  1262.         if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_SW )
  1263.         {
  1264.             // If using a SW rast then try to find a low resolution and 16-bpp.
  1265.             BOOL bFound16BitMode = FALSE;            
  1266.             DWORD dwSmallestHeight = -1;
  1267.             pD3DDeviceInfo->dwCurrentMode = 0; // unless we find something better
  1268.  
  1269.             for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
  1270.             {
  1271.                 pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  1272.  
  1273.                 // Skip 640x400 because 640x480 is better
  1274.                 if( pD3DModeInfo->Height == 400 )
  1275.                     continue; 
  1276.  
  1277.                 if( pD3DModeInfo->Height < dwSmallestHeight || 
  1278.                     (pD3DModeInfo->Height == dwSmallestHeight && !bFound16BitMode) )
  1279.                 {
  1280.                     dwSmallestHeight = pD3DModeInfo->Height;
  1281.                     pD3DDeviceInfo->dwCurrentMode = iMode;
  1282.                     bFound16BitMode = FALSE;
  1283.  
  1284.                     if( ( pD3DModeInfo->Format == D3DFMT_R5G6B5 ||
  1285.                           pD3DModeInfo->Format == D3DFMT_X1R5G5B5 || 
  1286.                           pD3DModeInfo->Format == D3DFMT_A1R5G5B5 || 
  1287.                           pD3DModeInfo->Format == D3DFMT_A4R4G4B4 || 
  1288.                           pD3DModeInfo->Format == D3DFMT_X4R4G4B4 ) )
  1289.                     {
  1290.                         bFound16BitMode = TRUE;
  1291.                     }
  1292.                 }
  1293.             }
  1294.         }
  1295.         else
  1296.         {
  1297.             // Try to find mode matching desktop resolution and 32-bpp.
  1298.             BOOL bMatchedSize = FALSE;
  1299.             BOOL bGot32Bit = FALSE;
  1300.             pD3DDeviceInfo->dwCurrentMode = 0; // unless we find something better
  1301.             for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
  1302.             {
  1303.                 pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  1304.                 if( pD3DModeInfo->Width == pD3DAdapterInfo->d3ddmDesktop.Width &&
  1305.                     pD3DModeInfo->Height == pD3DAdapterInfo->d3ddmDesktop.Height )
  1306.                 {
  1307.                     if( !bMatchedSize )
  1308.                         pD3DDeviceInfo->dwCurrentMode = iMode;
  1309.                     bMatchedSize = TRUE;
  1310.                     if( !bGot32Bit &&
  1311.                         ( pD3DModeInfo->Format == D3DFMT_X8R8G8B8 ||
  1312.                           pD3DModeInfo->Format == D3DFMT_A8R8G8B8 ) )
  1313.                     {
  1314.                         pD3DDeviceInfo->dwCurrentMode = iMode;
  1315.                         bGot32Bit = TRUE;
  1316.                         break;
  1317.                     }
  1318.                 }
  1319.             }
  1320.         }
  1321.     }
  1322.  
  1323.     // If desktop mode not found, pick highest mode available
  1324.     if( pD3DDeviceInfo->dwCurrentMode == 0xffff )
  1325.     {
  1326.         DWORD dwWidthMax = 0;
  1327.         DWORD dwHeightMax = 0;
  1328.         DWORD dwBppMax = 0;
  1329.         DWORD dwWidthCur = 0;
  1330.         DWORD dwHeightCur = 0;
  1331.         DWORD dwBppCur = 0;
  1332.         for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
  1333.         {
  1334.             pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  1335.             dwWidthCur = pD3DModeInfo->Width;
  1336.             dwHeightCur = pD3DModeInfo->Height;
  1337.             if( pD3DModeInfo->Format == D3DFMT_X8R8G8B8 ||
  1338.                 pD3DModeInfo->Format == D3DFMT_A8R8G8B8 )
  1339.             {
  1340.                 dwBppCur = 32;
  1341.             }
  1342.             else
  1343.             {
  1344.                 dwBppCur = 16;
  1345.             }
  1346.             if( dwWidthCur > dwWidthMax ||
  1347.                 dwHeightCur > dwHeightMax ||
  1348.                 dwWidthCur == dwWidthMax && dwHeightCur == dwHeightMax && dwBppCur > dwBppMax )
  1349.             {
  1350.                 dwWidthMax = dwWidthCur;
  1351.                 dwHeightMax = dwHeightCur;
  1352.                 dwBppMax = dwBppCur;
  1353.                 pD3DDeviceInfo->dwCurrentMode = iMode;
  1354.             }
  1355.         }
  1356.     }
  1357.  
  1358.     // Try to create the D3D device, falling back to lower-res modes if it fails
  1359.     BOOL bAtLeastOneFailure = FALSE;
  1360.     while( TRUE )
  1361.     {
  1362.         pD3DModeInfo = &pD3DDeviceInfo->modes[pD3DDeviceInfo->dwCurrentMode];
  1363.         pRenderUnit->DeviceType = pD3DDeviceInfo->DeviceType;
  1364.         pRenderUnit->dwBehavior = pD3DModeInfo->dwBehavior;
  1365.         pRenderUnit->iMonitor = iMonitor;
  1366.         pRenderUnit->d3dpp.BackBufferFormat = pD3DModeInfo->Format;
  1367.         pRenderUnit->d3dpp.BackBufferWidth = pD3DModeInfo->Width;
  1368.         pRenderUnit->d3dpp.BackBufferHeight = pD3DModeInfo->Height;
  1369.         pRenderUnit->d3dpp.Windowed = FALSE;
  1370.         pRenderUnit->d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
  1371.         pRenderUnit->d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  1372.         pRenderUnit->d3dpp.AutoDepthStencilFormat = pD3DModeInfo->DepthStencilFormat;
  1373.         pRenderUnit->d3dpp.BackBufferCount = 1;
  1374.         pRenderUnit->d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
  1375.         pRenderUnit->d3dpp.SwapEffect = m_SwapEffectFullscreen;
  1376.         pRenderUnit->d3dpp.hDeviceWindow = pD3DAdapterInfo->hWndDevice;
  1377.         pRenderUnit->d3dpp.EnableAutoDepthStencil = m_bUseDepthBuffer;
  1378.         pRenderUnit->d3dpp.Flags = 0;
  1379.  
  1380.         // Create device
  1381.         hr = m_pD3D->CreateDevice( iAdapter, pRenderUnit->DeviceType, 
  1382.                                    m_hWnd, // (this is the focus window)
  1383.                                    pRenderUnit->dwBehavior, &pRenderUnit->d3dpp, 
  1384.                                    &pRenderUnit->pd3dDevice );
  1385.         if( SUCCEEDED( hr ) )
  1386.         {
  1387.             // Give the client app an opportunity to reject this mode
  1388.             // due to not enough video memory, or any other reason
  1389.             if( SUCCEEDED( hr = ConfirmMode( pRenderUnit->pd3dDevice ) ) )
  1390.                 break;
  1391.             else
  1392.                 SAFE_RELEASE( pRenderUnit->pd3dDevice );
  1393.         }
  1394.  
  1395.         // If we get here, remember that CreateDevice or ConfirmMode failed, so
  1396.         // we can change the default mode next time
  1397.         bAtLeastOneFailure = TRUE;
  1398.  
  1399.         if( !FindNextLowerMode( pD3DDeviceInfo ) )
  1400.             break;
  1401.     }
  1402.  
  1403.     if( SUCCEEDED( hr ) && bAtLeastOneFailure && m_strRegPath[0] != TEXT('\0') )
  1404.     {
  1405.         // Record the mode that succeeded in the registry so we can 
  1406.         // default to it next time
  1407.         TCHAR strKey[100];
  1408.         HKEY hkeyParent;
  1409.         HKEY hkey;
  1410.  
  1411.         pD3DAdapterInfo->dwUserPrefWidth = pRenderUnit->d3dpp.BackBufferWidth;
  1412.         pD3DAdapterInfo->dwUserPrefHeight = pRenderUnit->d3dpp.BackBufferHeight;
  1413.         pD3DAdapterInfo->d3dfmtUserPrefFormat = pRenderUnit->d3dpp.BackBufferFormat;
  1414.  
  1415.         if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, m_strRegPath, 
  1416.             0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyParent, NULL ) )
  1417.         {
  1418.             wsprintf( strKey, TEXT("Screen %d"), iMonitor + 1 );
  1419.             if( ERROR_SUCCESS == RegCreateKeyEx( hkeyParent, strKey, 
  1420.                 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  1421.             {
  1422.                 RegSetValueEx( hkey, TEXT("Width"), NULL, REG_DWORD, 
  1423.                     (BYTE*)&pD3DAdapterInfo->dwUserPrefWidth, sizeof(DWORD) );
  1424.                 RegSetValueEx( hkey, TEXT("Height"), NULL, REG_DWORD, 
  1425.                     (BYTE*)&pD3DAdapterInfo->dwUserPrefHeight, sizeof(DWORD) );
  1426.                 RegSetValueEx( hkey, TEXT("Format"), NULL, REG_DWORD, 
  1427.                     (BYTE*)&pD3DAdapterInfo->d3dfmtUserPrefFormat, sizeof(DWORD) );
  1428.                 RegSetValueEx( hkey, TEXT("Adapter ID"), NULL, REG_BINARY, 
  1429.                     (BYTE*)&pD3DAdapterInfo->d3dAdapterIdentifier.DeviceIdentifier, sizeof(GUID) );
  1430.                 RegCloseKey( hkey );
  1431.             }
  1432.             RegCloseKey( hkeyParent );
  1433.         }
  1434.     }
  1435.  
  1436.     return hr;
  1437. }
  1438.  
  1439.  
  1440.  
  1441.  
  1442. //-----------------------------------------------------------------------------
  1443. // Name: FindNextLowerMode()
  1444. // Desc: 
  1445. //-----------------------------------------------------------------------------
  1446. BOOL CD3DScreensaver::FindNextLowerMode( D3DDeviceInfo* pD3DDeviceInfo )
  1447. {
  1448.     DWORD iModeCur = pD3DDeviceInfo->dwCurrentMode;
  1449.     D3DModeInfo* pD3DModeInfoCur = &pD3DDeviceInfo->modes[iModeCur];
  1450.     DWORD dwWidthCur = pD3DModeInfoCur->Width;
  1451.     DWORD dwHeightCur = pD3DModeInfoCur->Height;
  1452.     DWORD dwNumPixelsCur = dwWidthCur * dwHeightCur;
  1453.     D3DFORMAT d3dfmtCur = pD3DModeInfoCur->Format;
  1454.     BOOL b32BitCur = (d3dfmtCur == D3DFMT_A8R8G8B8 ||
  1455.                       d3dfmtCur == D3DFMT_X8R8G8B8);
  1456.     DWORD iModeNew;
  1457.     D3DModeInfo* pD3DModeInfoNew;
  1458.     DWORD dwWidthNew;
  1459.     DWORD dwHeightNew;
  1460.     DWORD dwNumPixelsNew;
  1461.     D3DFORMAT d3dfmtNew = D3DFMT_UNKNOWN;
  1462.     BOOL b32BitNew;
  1463.  
  1464.     DWORD dwWidthBest = 0;
  1465.     DWORD dwHeightBest = 0;
  1466.     DWORD dwNumPixelsBest = 0;
  1467.     BOOL b32BitBest = FALSE;
  1468.     DWORD iModeBest = 0xffff;
  1469.  
  1470.     for( iModeNew = 0; iModeNew < pD3DDeviceInfo->dwNumModes; iModeNew++ )
  1471.     {
  1472.         // Don't pick the same mode we currently have
  1473.         if( iModeNew == iModeCur )
  1474.             continue;
  1475.  
  1476.         // Get info about new mode
  1477.         pD3DModeInfoNew = &pD3DDeviceInfo->modes[iModeNew];
  1478.         dwWidthNew = pD3DModeInfoNew->Width;
  1479.         dwHeightNew = pD3DModeInfoNew->Height;
  1480.         dwNumPixelsNew = dwWidthNew * dwHeightNew;
  1481.         d3dfmtNew = pD3DModeInfoNew->Format;
  1482.         b32BitNew = (d3dfmtNew == D3DFMT_A8R8G8B8 ||
  1483.                      d3dfmtNew == D3DFMT_X8R8G8B8);
  1484.  
  1485.         // If we're currently 32-bit and new mode is same width/height and 16-bit, take it
  1486.         if( b32BitCur && 
  1487.             !b32BitNew &&
  1488.             pD3DModeInfoNew->Width == dwWidthCur &&
  1489.             pD3DModeInfoNew->Height == dwHeightCur)
  1490.         {
  1491.             pD3DDeviceInfo->dwCurrentMode = iModeNew;
  1492.             return TRUE;
  1493.         }
  1494.  
  1495.         // If new mode is smaller than current mode, see if it's our best so far
  1496.         if( dwNumPixelsNew < dwNumPixelsCur )
  1497.         {
  1498.             // If current best is 32-bit, new mode needs to be bigger to be best
  1499.             if( b32BitBest && (dwNumPixelsNew < dwNumPixelsBest ) )
  1500.                 continue;
  1501.  
  1502.             // If new mode is bigger or equal to best, make it the best
  1503.             if( (dwNumPixelsNew > dwNumPixelsBest) || 
  1504.                 (!b32BitBest && b32BitNew) )
  1505.             {
  1506.                 dwWidthBest = dwWidthNew;
  1507.                 dwHeightBest = dwHeightNew;
  1508.                 dwNumPixelsBest = dwNumPixelsNew;
  1509.                 iModeBest = iModeNew;
  1510.                 b32BitBest = b32BitNew;
  1511.             }
  1512.         }
  1513.     }
  1514.     if( iModeBest == 0xffff )
  1515.         return FALSE; // no smaller mode found
  1516.     pD3DDeviceInfo->dwCurrentMode = iModeBest;
  1517.     return TRUE;
  1518. }
  1519.  
  1520.  
  1521.  
  1522.  
  1523. //-----------------------------------------------------------------------------
  1524. // Name: CreateWindowedRenderUnit()
  1525. // Desc: 
  1526. //-----------------------------------------------------------------------------
  1527. HRESULT CD3DScreensaver::CreateWindowedRenderUnit( RenderUnit* pRenderUnit )
  1528. {
  1529.     HRESULT hr;
  1530.     UINT iAdapter = pRenderUnit->iAdapter;
  1531.     D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
  1532.     DWORD iMonitor = pD3DAdapterInfo->iMonitor;
  1533.     D3DDeviceInfo* pD3DDeviceInfo;
  1534.     D3DDEVTYPE curType;
  1535.  
  1536.     // Find the best device for the primary adapter.  Use HAL
  1537.     // if it's there, otherwise SW, otherwise REF.
  1538.     pD3DAdapterInfo->dwCurrentDevice = 0xffff; // unless we find something better
  1539.     curType = D3DDEVTYPE_FORCE_DWORD;
  1540.     for( DWORD iDevice = 0; iDevice < pD3DAdapterInfo->dwNumDevices; iDevice++)
  1541.     {
  1542.         pD3DDeviceInfo = &pD3DAdapterInfo->devices[iDevice];
  1543.         if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_HAL && !pD3DAdapterInfo->bDisableHW &&
  1544.             pD3DDeviceInfo->bCanDoWindowed )
  1545.         {
  1546.             pD3DAdapterInfo->dwCurrentDevice = iDevice;
  1547.             curType = D3DDEVTYPE_HAL;
  1548.             break;
  1549.         }
  1550.         else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_SW &&
  1551.             pD3DDeviceInfo->bCanDoWindowed )
  1552.         {
  1553.             pD3DAdapterInfo->dwCurrentDevice = iDevice;
  1554.             curType = D3DDEVTYPE_SW;
  1555.             // but keep looking
  1556.         }
  1557.         else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_REF && m_bAllowRef && curType != D3DDEVTYPE_SW )
  1558.         {
  1559.             pD3DAdapterInfo->dwCurrentDevice = iDevice;
  1560.             curType = D3DDEVTYPE_REF;
  1561.             // but keep looking
  1562.         }
  1563.     }
  1564.     if( pD3DAdapterInfo->dwCurrentDevice == 0xffff )
  1565.         return D3DAPPERR_NOHARDWAREDEVICE;
  1566.     pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
  1567.  
  1568.     D3DWindowedModeInfo D3DWindowedModeInfo;
  1569.  
  1570.     D3DWindowedModeInfo.DisplayFormat = pD3DAdapterInfo->d3ddmDesktop.Format;
  1571.     D3DWindowedModeInfo.BackBufferFormat = pD3DAdapterInfo->d3ddmDesktop.Format;
  1572.     if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1573.     {
  1574.         D3DWindowedModeInfo.BackBufferFormat = D3DFMT_A8R8G8B8;
  1575.         if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1576.         {
  1577.             D3DWindowedModeInfo.BackBufferFormat = D3DFMT_X8R8G8B8;
  1578.             if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1579.             {
  1580.                 D3DWindowedModeInfo.BackBufferFormat = D3DFMT_A1R5G5B5;
  1581.                 if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1582.                 {
  1583.                     D3DWindowedModeInfo.BackBufferFormat = D3DFMT_R5G6B5;
  1584.                     if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1585.                     {
  1586.                         return E_FAIL;
  1587.                     }
  1588.                 }
  1589.             }
  1590.         }
  1591.     }
  1592.  
  1593.     pRenderUnit->DeviceType = pD3DDeviceInfo->DeviceType;
  1594.     pRenderUnit->dwBehavior = D3DWindowedModeInfo.dwBehavior;
  1595.     pRenderUnit->iMonitor = iMonitor;
  1596.     pRenderUnit->d3dpp.BackBufferWidth = 0;
  1597.     pRenderUnit->d3dpp.BackBufferHeight = 0;
  1598.     pRenderUnit->d3dpp.Windowed = TRUE;
  1599.     pRenderUnit->d3dpp.FullScreen_RefreshRateInHz = 0;
  1600.     pRenderUnit->d3dpp.FullScreen_PresentationInterval = 0;
  1601.     pRenderUnit->d3dpp.BackBufferFormat = D3DWindowedModeInfo.BackBufferFormat;
  1602.     pRenderUnit->d3dpp.AutoDepthStencilFormat = D3DWindowedModeInfo.DepthStencilFormat;
  1603.     pRenderUnit->d3dpp.BackBufferCount = 1;
  1604.     pRenderUnit->d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
  1605.     pRenderUnit->d3dpp.SwapEffect = m_SwapEffectWindowed;
  1606.     pRenderUnit->d3dpp.hDeviceWindow = pD3DAdapterInfo->hWndDevice;
  1607.     pRenderUnit->d3dpp.EnableAutoDepthStencil = m_bUseDepthBuffer;
  1608.     pRenderUnit->d3dpp.Flags = 0;
  1609.     // Create device
  1610.     hr = m_pD3D->CreateDevice( iAdapter, pRenderUnit->DeviceType, m_hWnd,
  1611.                                pRenderUnit->dwBehavior, &pRenderUnit->d3dpp, &pRenderUnit->pd3dDevice );
  1612.     if ( FAILED(hr) )
  1613.     {
  1614.         return hr;
  1615.     }
  1616.  
  1617.     return S_OK;
  1618. }
  1619.  
  1620.  
  1621.  
  1622.  
  1623. //-----------------------------------------------------------------------------
  1624. // Name: UpdateDeviceStats()
  1625. // Desc: Store device description
  1626. //-----------------------------------------------------------------------------
  1627. VOID CD3DScreensaver::UpdateDeviceStats()
  1628. {
  1629.     DWORD iRenderUnit;
  1630.     RenderUnit* pRenderUnit; 
  1631.     for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  1632.     {
  1633.         pRenderUnit = &m_RenderUnits[iRenderUnit];
  1634.         if( pRenderUnit->DeviceType == D3DDEVTYPE_REF )
  1635.             lstrcpy( pRenderUnit->strDeviceStats, TEXT("REF") );
  1636.         else if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1637.             lstrcpy( pRenderUnit->strDeviceStats, TEXT("HAL") );
  1638.         else if( pRenderUnit->DeviceType == D3DDEVTYPE_SW )
  1639.             lstrcpy( pRenderUnit->strDeviceStats, TEXT("SW") );
  1640.  
  1641.         if( pRenderUnit->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING &&
  1642.             pRenderUnit->dwBehavior & D3DCREATE_PUREDEVICE )
  1643.         {
  1644.             if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1645.                 lstrcat( pRenderUnit->strDeviceStats, TEXT(" (pure hw vp)") );
  1646.             else
  1647.                 lstrcat( pRenderUnit->strDeviceStats, TEXT(" (simulated pure hw vp)") );
  1648.         }
  1649.         else if( pRenderUnit->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING )
  1650.         {
  1651.             if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1652.                 lstrcat( pRenderUnit->strDeviceStats, TEXT(" (hw vp)") );
  1653.             else
  1654.                 lstrcat( pRenderUnit->strDeviceStats, TEXT(" (simulated hw vp)") );
  1655.         }
  1656.         else if( pRenderUnit->dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING )
  1657.         {
  1658.             if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1659.                 lstrcat( pRenderUnit->strDeviceStats, TEXT(" (mixed vp)") );
  1660.             else
  1661.                 lstrcat( pRenderUnit->strDeviceStats, TEXT(" (simulated mixed vp)") );
  1662.         }
  1663.         else if( pRenderUnit->dwBehavior & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
  1664.         {
  1665.             lstrcat( pRenderUnit->strDeviceStats, TEXT(" (sw vp)") );
  1666.         }
  1667.  
  1668.         if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1669.         {
  1670.             lstrcat( pRenderUnit->strDeviceStats, TEXT(": ") );
  1671.             TCHAR szDescription[300];
  1672.             DXUtil_ConvertAnsiStringToGeneric( szDescription, 
  1673.                 m_Adapters[pRenderUnit->iAdapter]->d3dAdapterIdentifier.Description, 300 );
  1674.             lstrcat( pRenderUnit->strDeviceStats, szDescription );
  1675.         }
  1676.     }
  1677. }
  1678.  
  1679.  
  1680.  
  1681.  
  1682. //-----------------------------------------------------------------------------
  1683. // Name: SwitchToRenderUnit()
  1684. // Desc: Updates internal variables and notifies client that we are switching
  1685. //       to a new RenderUnit / D3D device.
  1686. //-----------------------------------------------------------------------------
  1687. VOID CD3DScreensaver::SwitchToRenderUnit( UINT iRenderUnit )
  1688. {
  1689.     RenderUnit* pRenderUnit = &m_RenderUnits[iRenderUnit];
  1690.     MonitorInfo* pMonitorInfo = &m_Monitors[pRenderUnit->iMonitor];
  1691.  
  1692.     m_pd3dDevice = pRenderUnit->pd3dDevice;
  1693.     if( !m_bWindowed )
  1694.         m_rcRenderCurDevice = pMonitorInfo->rcScreen;
  1695.  
  1696.     if( m_pd3dDevice != NULL )
  1697.     {
  1698.         // Store render target surface desc
  1699.         LPDIRECT3DSURFACE8 pBackBuffer;
  1700.         m_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  1701.         pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
  1702.         pBackBuffer->Release();
  1703.     }
  1704.  
  1705.     lstrcpy( m_strDeviceStats, pRenderUnit->strDeviceStats );
  1706.     lstrcpy( m_strFrameStats, pRenderUnit->strFrameStats );
  1707.  
  1708.     // Notify the client to switch to this device
  1709.     SetDevice(iRenderUnit);
  1710. }
  1711.  
  1712.  
  1713.  
  1714.  
  1715. //-----------------------------------------------------------------------------
  1716. // Name: BuildProjectionMatrix()
  1717. // Desc: This function sets up an appropriate projection matrix to support 
  1718. //       rendering the appropriate parts of the scene to each screen.
  1719. //-----------------------------------------------------------------------------
  1720. VOID CD3DScreensaver::BuildProjectionMatrix( FLOAT fNear, FLOAT fFar, D3DXMATRIX* pMatrix )
  1721. {
  1722.     D3DXMATRIX mat;
  1723.     INT cx, cy;
  1724.     INT dx, dy;
  1725.     INT dd;
  1726.     FLOAT l,r,t,b;
  1727.  
  1728.     if( m_bAllScreensSame )
  1729.     {
  1730.         cx = (m_rcRenderCurDevice.right + m_rcRenderCurDevice.left) / 2;
  1731.         cy = (m_rcRenderCurDevice.bottom + m_rcRenderCurDevice.top) / 2;
  1732.         dx = m_rcRenderCurDevice.right - m_rcRenderCurDevice.left;
  1733.         dy = m_rcRenderCurDevice.bottom - m_rcRenderCurDevice.top;
  1734.     }
  1735.     else
  1736.     {
  1737.         cx = (m_rcRenderTotal.right + m_rcRenderTotal.left) / 2;
  1738.         cy = (m_rcRenderTotal.bottom + m_rcRenderTotal.top) / 2;
  1739.         dx = m_rcRenderTotal.right - m_rcRenderTotal.left;
  1740.         dy = m_rcRenderTotal.bottom - m_rcRenderTotal.top;
  1741.     }
  1742.  
  1743.     dd = (dx > dy ? dy : dx);
  1744.  
  1745.     l = FLOAT(m_rcRenderCurDevice.left - cx) / (FLOAT)(dd);
  1746.     r = FLOAT(m_rcRenderCurDevice.right - cx) / (FLOAT)(dd);
  1747.     t = FLOAT(m_rcRenderCurDevice.top - cy) / (FLOAT)(dd);
  1748.     b = FLOAT(m_rcRenderCurDevice.bottom - cy) / (FLOAT)(dd);
  1749.  
  1750.     l = fNear * l;
  1751.     r = fNear * r;
  1752.     t = fNear * t;
  1753.     b = fNear * b;
  1754.  
  1755.     D3DXMatrixPerspectiveOffCenterLH( &mat, l, r, t, b, fNear, fFar );
  1756.     *pMatrix = mat;
  1757. }
  1758.  
  1759.  
  1760.  
  1761.  
  1762. //-----------------------------------------------------------------------------
  1763. // Name: SetProjectionMatrix()
  1764. // Desc: This function sets up an appropriate projection matrix to support 
  1765. //       rendering the appropriate parts of the scene to each screen.
  1766. //-----------------------------------------------------------------------------
  1767. HRESULT CD3DScreensaver::SetProjectionMatrix( FLOAT fNear, FLOAT fFar )
  1768. {
  1769.     D3DXMATRIX mat;
  1770.     BuildProjectionMatrix( fNear, fFar, &mat );
  1771.     return m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &mat );
  1772. }
  1773.  
  1774.  
  1775.  
  1776.  
  1777. //-----------------------------------------------------------------------------
  1778. // Name: SortModesCallback()
  1779. // Desc: Callback function for sorting display modes (used by BuildDeviceList).
  1780. //-----------------------------------------------------------------------------
  1781. static int SortModesCallback( const VOID* arg1, const VOID* arg2 )
  1782. {
  1783.     D3DDISPLAYMODE* p1 = (D3DDISPLAYMODE*)arg1;
  1784.     D3DDISPLAYMODE* p2 = (D3DDISPLAYMODE*)arg2;
  1785.  
  1786.     if( p1->Width  < p2->Width )    return -1;
  1787.     if( p1->Width  > p2->Width )    return +1;
  1788.     if( p1->Height < p2->Height )   return -1;
  1789.     if( p1->Height > p2->Height )   return +1;
  1790.     if( p1->Format > p2->Format )   return -1;
  1791.     if( p1->Format < p2->Format )   return +1;
  1792.  
  1793.     return 0;
  1794. }
  1795.  
  1796.  
  1797.  
  1798.  
  1799. //-----------------------------------------------------------------------------
  1800. // Name: BuildDeviceList()
  1801. // Desc: Builds a list of all available adapters, devices, and modes.
  1802. //-----------------------------------------------------------------------------
  1803. HRESULT CD3DScreensaver::BuildDeviceList()
  1804. {
  1805.     DWORD dwNumDeviceTypes;
  1806.     const TCHAR* strDeviceDescs[] = { TEXT("HAL"), TEXT("SW"), TEXT("REF") };
  1807.     const D3DDEVTYPE DeviceTypes[] = { D3DDEVTYPE_HAL, D3DDEVTYPE_SW, D3DDEVTYPE_REF };
  1808.     if( m_bAllowRef )
  1809.         dwNumDeviceTypes = 3;
  1810.     else
  1811.         dwNumDeviceTypes = 2;
  1812.  
  1813.     HMONITOR hMonitor = NULL;
  1814.     BOOL bHALExists = FALSE;
  1815.     BOOL bHALIsWindowedCompatible = FALSE;
  1816.     BOOL bHALIsDesktopCompatible = FALSE;
  1817.     BOOL bHALIsSampleCompatible = FALSE;
  1818.  
  1819.     // Loop through all the adapters on the system (usually, there's just one
  1820.     // unless more than one graphics card is present).
  1821.     for( UINT iAdapter = 0; iAdapter < m_pD3D->GetAdapterCount(); iAdapter++ )
  1822.     {
  1823.         // Fill in adapter info
  1824.         if( m_Adapters[m_dwNumAdapters] == NULL )
  1825.         {
  1826.             m_Adapters[m_dwNumAdapters] = new D3DAdapterInfo;
  1827.             if( m_Adapters[m_dwNumAdapters] == NULL )
  1828.                 return E_OUTOFMEMORY;
  1829.             ZeroMemory( m_Adapters[m_dwNumAdapters], sizeof(D3DAdapterInfo) );
  1830.         }
  1831.  
  1832.         D3DAdapterInfo* pAdapter  = m_Adapters[m_dwNumAdapters];
  1833.         m_pD3D->GetAdapterIdentifier( iAdapter, D3DENUM_NO_WHQL_LEVEL, &pAdapter->d3dAdapterIdentifier );
  1834.         m_pD3D->GetAdapterDisplayMode( iAdapter, &pAdapter->d3ddmDesktop );
  1835.         pAdapter->dwNumDevices    = 0;
  1836.         pAdapter->dwCurrentDevice = 0;
  1837.         pAdapter->bLeaveBlack = FALSE;
  1838.         pAdapter->iMonitor = NO_MONITOR;
  1839.  
  1840.         // Find the MonitorInfo that corresponds to this adapter.  If the monitor
  1841.         // is disabled, the adapter has a NULL HMONITOR and we cannot find the 
  1842.         // corresponding MonitorInfo.  (Well, if one monitor was disabled, we
  1843.         // could link the one MonitorInfo with a NULL HMONITOR to the one
  1844.         // D3DAdapterInfo with a NULL HMONITOR, but if there are more than one,
  1845.         // we can't link them, so it's safer not to ever try.)
  1846.         hMonitor = m_pD3D->GetAdapterMonitor( iAdapter );
  1847.         if( hMonitor != NULL )
  1848.         {
  1849.             for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  1850.             {
  1851.                 MonitorInfo* pMonitorInfo;
  1852.                 pMonitorInfo = &m_Monitors[iMonitor];
  1853.                 if( pMonitorInfo->hMonitor == hMonitor )
  1854.                 {
  1855.                     pAdapter->iMonitor = iMonitor;
  1856.                     pMonitorInfo->iAdapter = iAdapter;
  1857.                     break;
  1858.                 }
  1859.             }
  1860.         }
  1861.  
  1862.         // Enumerate all display modes on this adapter
  1863.         D3DDISPLAYMODE modes[100];
  1864.         D3DFORMAT      formats[20];
  1865.         DWORD dwNumFormats      = 0;
  1866.         DWORD dwNumModes        = 0;
  1867.         DWORD dwNumAdapterModes = m_pD3D->GetAdapterModeCount( iAdapter );
  1868.  
  1869.         // Add the adapter's current desktop format to the list of formats
  1870.         formats[dwNumFormats++] = pAdapter->d3ddmDesktop.Format;
  1871.  
  1872.         for( UINT iMode = 0; iMode < dwNumAdapterModes; iMode++ )
  1873.         {
  1874.             // Get the display mode attributes
  1875.             D3DDISPLAYMODE DisplayMode;
  1876.             m_pD3D->EnumAdapterModes( iAdapter, iMode, &DisplayMode );
  1877.  
  1878.             // Filter out low-resolution modes
  1879.             if( DisplayMode.Width  < 640 || DisplayMode.Height < 400 )
  1880.                 continue;
  1881.  
  1882.             // Check if the mode already exists (to filter out refresh rates)
  1883.             for( DWORD m=0L; m<dwNumModes; m++ )
  1884.             {
  1885.                 if( ( modes[m].Width  == DisplayMode.Width  ) &&
  1886.                     ( modes[m].Height == DisplayMode.Height ) &&
  1887.                     ( modes[m].Format == DisplayMode.Format ) )
  1888.                     break;
  1889.             }
  1890.  
  1891.             // If we found a new mode, add it to the list of modes
  1892.             if( m == dwNumModes )
  1893.             {
  1894.                 modes[dwNumModes].Width       = DisplayMode.Width;
  1895.                 modes[dwNumModes].Height      = DisplayMode.Height;
  1896.                 modes[dwNumModes].Format      = DisplayMode.Format;
  1897.                 modes[dwNumModes].RefreshRate = 0;
  1898.                 dwNumModes++;
  1899.  
  1900.                 // Check if the mode's format already exists
  1901.                 for( DWORD f=0; f<dwNumFormats; f++ )
  1902.                 {
  1903.                     if( DisplayMode.Format == formats[f] )
  1904.                         break;
  1905.                 }
  1906.  
  1907.                 // If the format is new, add it to the list
  1908.                 if( f== dwNumFormats )
  1909.                     formats[dwNumFormats++] = DisplayMode.Format;
  1910.             }
  1911.         }
  1912.  
  1913.         // Sort the list of display modes (by format, then width, then height)
  1914.         qsort( modes, dwNumModes, sizeof(D3DDISPLAYMODE), SortModesCallback );
  1915.  
  1916.         // Add devices to adapter
  1917.         for( UINT iDevice = 0; iDevice < dwNumDeviceTypes; iDevice++ )
  1918.         {
  1919.             // Fill in device info
  1920.             D3DDeviceInfo* pDevice;
  1921.             pDevice                 = &pAdapter->devices[pAdapter->dwNumDevices];
  1922.             pDevice->DeviceType     = DeviceTypes[iDevice];
  1923.             m_pD3D->GetDeviceCaps( iAdapter, DeviceTypes[iDevice], &pDevice->d3dCaps );
  1924.             pDevice->strDesc        = strDeviceDescs[iDevice];
  1925.             pDevice->dwNumModes     = 0;
  1926.             pDevice->dwCurrentMode  = 0;
  1927.             pDevice->bCanDoWindowed = FALSE;
  1928.             pDevice->bWindowed      = FALSE;
  1929.             pDevice->MultiSampleType = D3DMULTISAMPLE_NONE;
  1930.  
  1931.             // Examine each format supported by the adapter to see if it will
  1932.             // work with this device and meets the needs of the application.
  1933.             BOOL  bFormatConfirmed[20];
  1934.             DWORD dwBehavior[20];
  1935.             D3DFORMAT fmtDepthStencil[20];
  1936.  
  1937.             for( DWORD f=0; f<dwNumFormats; f++ )
  1938.             {
  1939.                 bFormatConfirmed[f] = FALSE;
  1940.                 fmtDepthStencil[f] = D3DFMT_UNKNOWN;
  1941.  
  1942.                 // Skip formats that cannot be used as render targets on this device
  1943.                 if( FAILED( m_pD3D->CheckDeviceType( iAdapter, pDevice->DeviceType,
  1944.                                                      formats[f], formats[f], FALSE ) ) )
  1945.                     continue;
  1946.  
  1947.                 if( pDevice->DeviceType == D3DDEVTYPE_SW )
  1948.                 {
  1949.                     // This system has a SW device
  1950.                     pAdapter->bHasSW = TRUE;
  1951.                 }
  1952.  
  1953.                 if( pDevice->DeviceType == D3DDEVTYPE_HAL )
  1954.                 {
  1955.                     // This system has a HAL device
  1956.                     bHALExists = TRUE;
  1957.                     pAdapter->bHasHAL = TRUE;
  1958.  
  1959.                     if( pDevice->d3dCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED )
  1960.                     {
  1961.                         // HAL can run in a window for some mode
  1962.                         bHALIsWindowedCompatible = TRUE;
  1963.  
  1964.                         if( f == 0 )
  1965.                         {
  1966.                             // HAL can run in a window for the current desktop mode
  1967.                             bHALIsDesktopCompatible = TRUE;
  1968.                         }
  1969.                     }
  1970.                 }
  1971.  
  1972.                 // Confirm the device/format for HW vertex processing
  1973.                 if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT )
  1974.                 {
  1975.                     if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_PUREDEVICE )
  1976.                     {
  1977.                         dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING |
  1978.                                         D3DCREATE_PUREDEVICE;
  1979.  
  1980.                         if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  1981.                                                       formats[f] ) ) )
  1982.                             bFormatConfirmed[f] = TRUE;
  1983.                     }
  1984.  
  1985.                     if ( FALSE == bFormatConfirmed[f] )
  1986.                     {
  1987.                         dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  1988.  
  1989.                         if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  1990.                                                       formats[f] ) ) )
  1991.                             bFormatConfirmed[f] = TRUE;
  1992.                     }
  1993.  
  1994.                     if ( FALSE == bFormatConfirmed[f] )
  1995.                     {
  1996.                         dwBehavior[f] = D3DCREATE_MIXED_VERTEXPROCESSING;
  1997.  
  1998.                         if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  1999.                                                       formats[f] ) ) )
  2000.                             bFormatConfirmed[f] = TRUE;
  2001.                     }
  2002.                 }
  2003.  
  2004.                 // Confirm the device/format for SW vertex processing
  2005.                 if( FALSE == bFormatConfirmed[f] )
  2006.                 {
  2007.                     dwBehavior[f] = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  2008.  
  2009.                     if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  2010.                                                   formats[f] ) ) )
  2011.                         bFormatConfirmed[f] = TRUE;
  2012.                 }
  2013.  
  2014.                 if( bFormatConfirmed[f] && m_bMultithreaded )
  2015.                 {
  2016.                     dwBehavior[f] |= D3DCREATE_MULTITHREADED;
  2017.                 }
  2018.  
  2019.                 // Find a suitable depth/stencil buffer format for this device/format
  2020.                 if( bFormatConfirmed[f] && m_bUseDepthBuffer )
  2021.                 {
  2022.                     if( !FindDepthStencilFormat( iAdapter, pDevice->DeviceType,
  2023.                         formats[f], &fmtDepthStencil[f] ) )
  2024.                     {
  2025.                         bFormatConfirmed[f] = FALSE;
  2026.                     }
  2027.                 }
  2028.             }
  2029.  
  2030.             // Add all enumerated display modes with confirmed formats to the
  2031.             // device's list of valid modes
  2032.             for( DWORD m=0L; m<dwNumModes; m++ )
  2033.             {
  2034.                 for( DWORD f=0; f<dwNumFormats; f++ )
  2035.                 {
  2036.                     if( modes[m].Format == formats[f] )
  2037.                     {
  2038.                         if( bFormatConfirmed[f] == TRUE )
  2039.                         {
  2040.                             // Add this mode to the device's list of valid modes
  2041.                             pDevice->modes[pDevice->dwNumModes].Width      = modes[m].Width;
  2042.                             pDevice->modes[pDevice->dwNumModes].Height     = modes[m].Height;
  2043.                             pDevice->modes[pDevice->dwNumModes].Format     = modes[m].Format;
  2044.                             pDevice->modes[pDevice->dwNumModes].dwBehavior = dwBehavior[f];
  2045.                             pDevice->modes[pDevice->dwNumModes].DepthStencilFormat = fmtDepthStencil[f];
  2046.                             pDevice->dwNumModes++;
  2047.  
  2048.                             if( pDevice->DeviceType == D3DDEVTYPE_HAL )
  2049.                                 bHALIsSampleCompatible = TRUE;
  2050.                         }
  2051.                     }
  2052.                 }
  2053.             }
  2054.  
  2055.             // Select any 640x480 mode for default (but prefer a 16-bit mode)
  2056.             for( m=0; m<pDevice->dwNumModes; m++ )
  2057.             {
  2058.                 if( pDevice->modes[m].Width==640 && pDevice->modes[m].Height==480 )
  2059.                 {
  2060.                     pDevice->dwCurrentMode = m;
  2061.                     if( pDevice->modes[m].Format == D3DFMT_R5G6B5 ||
  2062.                         pDevice->modes[m].Format == D3DFMT_X1R5G5B5 ||
  2063.                         pDevice->modes[m].Format == D3DFMT_A1R5G5B5 )
  2064.                     {
  2065.                         break;
  2066.                     }
  2067.                 }
  2068.             }
  2069.  
  2070.             // Check if the device is compatible with the desktop display mode
  2071.             // (which was added initially as formats[0])
  2072.             if( bFormatConfirmed[0] && (pDevice->d3dCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED) )
  2073.             {
  2074.                 pDevice->bCanDoWindowed = TRUE;
  2075.                 pDevice->bWindowed      = TRUE;
  2076.             }
  2077.  
  2078.             // If valid modes were found, keep this device
  2079.             if( pDevice->dwNumModes > 0 )
  2080.             {
  2081.                 pAdapter->dwNumDevices++;
  2082.                 if( pDevice->DeviceType == D3DDEVTYPE_SW )
  2083.                     pAdapter->bHasAppCompatSW = TRUE;
  2084.                 else if( pDevice->DeviceType == D3DDEVTYPE_HAL )
  2085.                     pAdapter->bHasAppCompatHAL = TRUE;
  2086.             }
  2087.         }
  2088.  
  2089.         // If valid devices were found, keep this adapter
  2090. // Count adapters even if no devices, so we can throw up blank windows on them
  2091. //        if( pAdapter->dwNumDevices > 0 )
  2092.             m_dwNumAdapters++;
  2093.     }
  2094. /*
  2095.     // Return an error if no compatible devices were found
  2096.     if( 0L == m_dwNumAdapters )
  2097.         return D3DAPPERR_NOCOMPATIBLEDEVICES;
  2098.  
  2099.     // Pick a default device that can render into a window
  2100.     // (This code assumes that the HAL device comes before the REF
  2101.     // device in the device array).
  2102.     for( DWORD a=0; a<m_dwNumAdapters; a++ )
  2103.     {
  2104.         for( DWORD d=0; d < m_Adapters[a]->dwNumDevices; d++ )
  2105.         {
  2106.             if( m_Adapters[a]->devices[d].bWindowed )
  2107.             {
  2108.                 m_Adapters[a]->dwCurrentDevice = d;
  2109.                 m_dwAdapter = a;
  2110.                 m_bWindowed = TRUE;
  2111.  
  2112.                 // Display a warning message
  2113.                 if( m_Adapters[a]->devices[d].DeviceType == D3DDEVTYPE_REF )
  2114.                 {
  2115.                     if( !bHALExists )
  2116.                         DisplayErrorMsg( D3DAPPERR_NOHARDWAREDEVICE, MSGWARN_SWITCHEDTOREF );
  2117.                     else if( !bHALIsSampleCompatible )
  2118.                         DisplayErrorMsg( D3DAPPERR_HALNOTCOMPATIBLE, MSGWARN_SWITCHEDTOREF );
  2119.                     else if( !bHALIsWindowedCompatible )
  2120.                         DisplayErrorMsg( D3DAPPERR_NOWINDOWEDHAL, MSGWARN_SWITCHEDTOREF );
  2121.                     else if( !bHALIsDesktopCompatible )
  2122.                         DisplayErrorMsg( D3DAPPERR_NODESKTOPHAL, MSGWARN_SWITCHEDTOREF );
  2123.                     else // HAL is desktop compatible, but not sample compatible
  2124.                         DisplayErrorMsg( D3DAPPERR_NOHALTHISMODE, MSGWARN_SWITCHEDTOREF );
  2125.                 }
  2126.  
  2127.                 return S_OK;
  2128.             }
  2129.         }
  2130.     }
  2131.     return D3DAPPERR_NOWINDOWABLEDEVICES;
  2132. */
  2133.  
  2134.     return S_OK;
  2135. }
  2136.  
  2137.  
  2138.  
  2139.  
  2140. //-----------------------------------------------------------------------------
  2141. // Name: CheckWindowedFormat()
  2142. // Desc: 
  2143. //-----------------------------------------------------------------------------
  2144. HRESULT CD3DScreensaver::CheckWindowedFormat( UINT iAdapter, D3DWindowedModeInfo* pD3DWindowedModeInfo )
  2145. {
  2146.     HRESULT hr;
  2147.     D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
  2148.     D3DDeviceInfo* pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
  2149.     BOOL bFormatConfirmed = FALSE;
  2150.  
  2151.     if( FAILED( hr = m_pD3D->CheckDeviceType( iAdapter, pD3DDeviceInfo->DeviceType,
  2152.         pD3DAdapterInfo->d3ddmDesktop.Format, pD3DWindowedModeInfo->BackBufferFormat, TRUE ) ) )
  2153.     {
  2154.         return hr;
  2155.     }
  2156.  
  2157.     // Confirm the device/format for HW vertex processing
  2158.     if( pD3DDeviceInfo->d3dCaps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT )
  2159.     {
  2160.         if( pD3DDeviceInfo->d3dCaps.DevCaps&D3DDEVCAPS_PUREDEVICE )
  2161.         {
  2162.             pD3DWindowedModeInfo->dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING |
  2163.                             D3DCREATE_PUREDEVICE;
  2164.  
  2165.             if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
  2166.                                           pD3DWindowedModeInfo->BackBufferFormat ) ) )
  2167.                 bFormatConfirmed = TRUE;
  2168.         }
  2169.  
  2170.         if ( !bFormatConfirmed )
  2171.         {
  2172.             pD3DWindowedModeInfo->dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  2173.  
  2174.             if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
  2175.                                           pD3DWindowedModeInfo->BackBufferFormat ) ) )
  2176.                 bFormatConfirmed = TRUE;
  2177.         }
  2178.  
  2179.         if ( !bFormatConfirmed )
  2180.         {
  2181.             pD3DWindowedModeInfo->dwBehavior = D3DCREATE_MIXED_VERTEXPROCESSING;
  2182.  
  2183.             if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
  2184.                                           pD3DWindowedModeInfo->BackBufferFormat ) ) )
  2185.                 bFormatConfirmed = TRUE;
  2186.         }
  2187.     }
  2188.  
  2189.     // Confirm the device/format for SW vertex processing
  2190.     if( !bFormatConfirmed )
  2191.     {
  2192.         pD3DWindowedModeInfo->dwBehavior = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  2193.  
  2194.         if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
  2195.                                       pD3DWindowedModeInfo->BackBufferFormat ) ) )
  2196.             bFormatConfirmed = TRUE;
  2197.     }
  2198.  
  2199.     if( bFormatConfirmed && m_bMultithreaded )
  2200.     {
  2201.         pD3DWindowedModeInfo->dwBehavior |= D3DCREATE_MULTITHREADED;
  2202.     }
  2203.  
  2204.     // Find a suitable depth/stencil buffer format for this device/format
  2205.     if( bFormatConfirmed && m_bUseDepthBuffer )
  2206.     {
  2207.         if( !FindDepthStencilFormat( iAdapter, pD3DDeviceInfo->DeviceType,
  2208.             pD3DWindowedModeInfo->BackBufferFormat, &pD3DWindowedModeInfo->DepthStencilFormat ) )
  2209.         {
  2210.             bFormatConfirmed = FALSE;
  2211.         }
  2212.     }
  2213.  
  2214.     if( !bFormatConfirmed )
  2215.         return E_FAIL;
  2216.  
  2217.     return S_OK;
  2218. }
  2219.  
  2220.  
  2221.  
  2222.  
  2223. //-----------------------------------------------------------------------------
  2224. // Name: FindDepthStencilFormat()
  2225. // Desc: Finds a depth/stencil format for the given device that is compatible
  2226. //       with the render target format and meets the needs of the app.
  2227. //-----------------------------------------------------------------------------
  2228. BOOL CD3DScreensaver::FindDepthStencilFormat( UINT iAdapter, D3DDEVTYPE DeviceType,
  2229.     D3DFORMAT TargetFormat, D3DFORMAT* pDepthStencilFormat )
  2230. {
  2231.     if( m_dwMinDepthBits <= 16 && m_dwMinStencilBits == 0 )
  2232.     {
  2233.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  2234.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16 ) ) )
  2235.         {
  2236.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  2237.                 TargetFormat, TargetFormat, D3DFMT_D16 ) ) )
  2238.             {
  2239.                 *pDepthStencilFormat = D3DFMT_D16;
  2240.                 return TRUE;
  2241.             }
  2242.         }
  2243.     }
  2244.  
  2245.     if( m_dwMinDepthBits <= 15 && m_dwMinStencilBits <= 1 )
  2246.     {
  2247.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  2248.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D15S1 ) ) )
  2249.         {
  2250.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  2251.                 TargetFormat, TargetFormat, D3DFMT_D15S1 ) ) )
  2252.             {
  2253.                 *pDepthStencilFormat = D3DFMT_D15S1;
  2254.                 return TRUE;
  2255.             }
  2256.         }
  2257.     }
  2258.  
  2259.     if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits == 0 )
  2260.     {
  2261.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  2262.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X8 ) ) )
  2263.         {
  2264.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  2265.                 TargetFormat, TargetFormat, D3DFMT_D24X8 ) ) )
  2266.             {
  2267.                 *pDepthStencilFormat = D3DFMT_D24X8;
  2268.                 return TRUE;
  2269.             }
  2270.         }
  2271.     }
  2272.  
  2273.     if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 8 )
  2274.     {
  2275.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  2276.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24S8 ) ) )
  2277.         {
  2278.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  2279.                 TargetFormat, TargetFormat, D3DFMT_D24S8 ) ) )
  2280.             {
  2281.                 *pDepthStencilFormat = D3DFMT_D24S8;
  2282.                 return TRUE;
  2283.             }
  2284.         }
  2285.     }
  2286.  
  2287.     if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 4 )
  2288.     {
  2289.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  2290.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X4S4 ) ) )
  2291.         {
  2292.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  2293.                 TargetFormat, TargetFormat, D3DFMT_D24X4S4 ) ) )
  2294.             {
  2295.                 *pDepthStencilFormat = D3DFMT_D24X4S4;
  2296.                 return TRUE;
  2297.             }
  2298.         }
  2299.     }
  2300.  
  2301.     if( m_dwMinDepthBits <= 32 && m_dwMinStencilBits == 0 )
  2302.     {
  2303.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  2304.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D32 ) ) )
  2305.         {
  2306.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  2307.                 TargetFormat, TargetFormat, D3DFMT_D32 ) ) )
  2308.             {
  2309.                 *pDepthStencilFormat = D3DFMT_D32;
  2310.                 return TRUE;
  2311.             }
  2312.         }
  2313.     }
  2314.  
  2315.     return FALSE;
  2316. }
  2317.  
  2318.  
  2319.  
  2320.  
  2321. //-----------------------------------------------------------------------------
  2322. // Name: Cleanup3DEnvironment()
  2323. // Desc: 
  2324. //-----------------------------------------------------------------------------
  2325. VOID CD3DScreensaver::Cleanup3DEnvironment()
  2326. {
  2327.     RenderUnit* pRenderUnit;
  2328.  
  2329.     for( DWORD iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  2330.     {
  2331.         pRenderUnit = &m_RenderUnits[iRenderUnit];
  2332.         SwitchToRenderUnit( iRenderUnit );
  2333.         if( pRenderUnit->bDeviceObjectsRestored )
  2334.         {
  2335.             InvalidateDeviceObjects();
  2336.             pRenderUnit->bDeviceObjectsRestored = FALSE;
  2337.         }
  2338.         if( pRenderUnit->bDeviceObjectsInited )
  2339.         {
  2340.             DeleteDeviceObjects();
  2341.             pRenderUnit->bDeviceObjectsInited = FALSE;
  2342.         }
  2343.         SAFE_RELEASE(m_pd3dDevice);
  2344.     }
  2345.     m_dwNumRenderUnits = 0;
  2346.     SAFE_RELEASE(m_pD3D);
  2347. }
  2348.  
  2349.  
  2350.  
  2351.  
  2352. //-----------------------------------------------------------------------------
  2353. // Name: Render3DEnvironment()
  2354. // Desc: 
  2355. //-----------------------------------------------------------------------------
  2356. HRESULT CD3DScreensaver::Render3DEnvironment()
  2357. {
  2358.     HRESULT hr;
  2359.     RenderUnit* pRenderUnit;
  2360.     D3DAdapterInfo* pAdapterInfo;
  2361.  
  2362.     m_fTime        = DXUtil_Timer( TIMER_GETAPPTIME );
  2363.     m_fElapsedTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
  2364.  
  2365.  
  2366.     // Tell client to update the world
  2367.     FrameMove();
  2368.     UpdateFrameStats();
  2369.  
  2370.     for( DWORD iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  2371.     {
  2372.         pRenderUnit = &m_RenderUnits[iRenderUnit];
  2373.         pAdapterInfo = m_Adapters[pRenderUnit->iAdapter];
  2374.  
  2375.         SwitchToRenderUnit( iRenderUnit );
  2376.  
  2377.         if( m_pd3dDevice == NULL )
  2378.             continue;
  2379.  
  2380.         // Test the cooperative level to see if it's okay to render
  2381.         if( FAILED( hr = m_pd3dDevice->TestCooperativeLevel() ) )
  2382.         {
  2383.             // If the device was lost, do not render until we get it back
  2384.             if( D3DERR_DEVICELOST == hr )
  2385.                 return S_OK;
  2386.  
  2387.             // Check if the device needs to be reset.
  2388.             if( D3DERR_DEVICENOTRESET == hr )
  2389.             {
  2390.                 // If we are windowed, read the desktop mode and use the same format for
  2391.                 // the back buffer
  2392.                 if( m_bWindowed )
  2393.                 {
  2394.                     m_pD3D->GetAdapterDisplayMode( pRenderUnit->iAdapter, &pAdapterInfo->d3ddmDesktop );
  2395. //                    m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
  2396.                 }
  2397.  
  2398.                 if( pRenderUnit->bDeviceObjectsRestored )
  2399.                 {
  2400.                     InvalidateDeviceObjects();
  2401.                     pRenderUnit->bDeviceObjectsRestored = FALSE;
  2402.                 }
  2403.                 if( FAILED( hr = m_pd3dDevice->Reset( &pRenderUnit->d3dpp ) ) )
  2404.                 {
  2405.                     m_bErrorMode = TRUE;
  2406.                 }
  2407.                 else
  2408.                 {
  2409.                     if( FAILED( hr = RestoreDeviceObjects() ) )
  2410.                     {
  2411.                         m_bErrorMode = TRUE;
  2412.                     }
  2413.                     else
  2414.                     {
  2415.                         pRenderUnit->bDeviceObjectsRestored = TRUE;
  2416.                     }
  2417.                 }
  2418.             }
  2419.         }
  2420.  
  2421.         // Tell client to render using the current device
  2422.         Render();
  2423.     }
  2424.  
  2425.     // Call Present() in a separate loop once all rendering is done
  2426.     // so multiple monitors are as closely synced visually as possible
  2427.     for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  2428.     {
  2429.         pRenderUnit = &m_RenderUnits[iRenderUnit];
  2430.         SwitchToRenderUnit( iRenderUnit );
  2431.         // Present the results of the rendering to the screen
  2432.         m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
  2433.     }
  2434.  
  2435.     return S_OK;
  2436. }
  2437.  
  2438.  
  2439.  
  2440.  
  2441. //-----------------------------------------------------------------------------
  2442. // Name: UpdateErrorBox()
  2443. // Desc: Update the box that shows the error message
  2444. //-----------------------------------------------------------------------------
  2445. VOID CD3DScreensaver::UpdateErrorBox()
  2446. {
  2447.     MonitorInfo* pMonitorInfo;
  2448.     HWND hwnd;
  2449.     RECT rcBounds;
  2450.     static DWORD dwTimeLast = 0;
  2451.     DWORD dwTimeNow;
  2452.     FLOAT fTimeDelta;
  2453.  
  2454.     // Make sure all the RenderUnits / D3D devices have been torn down
  2455.     // so the error box is visible
  2456.     if( m_bErrorMode && m_dwNumRenderUnits > 0 )
  2457.     {
  2458.         Cleanup3DEnvironment();
  2459.     }
  2460.  
  2461.     // Update timing to determine how much to move error box
  2462.     if( dwTimeLast == 0 )
  2463.         dwTimeLast = timeGetTime();
  2464.     dwTimeNow = timeGetTime();
  2465.     fTimeDelta = (FLOAT)(dwTimeNow - dwTimeLast) / 1000.0f;
  2466.     dwTimeLast = dwTimeNow;
  2467.  
  2468.     // Load error string if necessary
  2469.     if( m_szError[0] == TEXT('\0') )
  2470.     {
  2471.         GetTextForError( m_hrError, m_szError, sizeof(m_szError) / sizeof(TCHAR) );
  2472.     }
  2473.  
  2474.     for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  2475.     {
  2476.         pMonitorInfo = &m_Monitors[iMonitor];
  2477.         hwnd = pMonitorInfo->hWnd;
  2478.         if( hwnd == NULL )
  2479.             continue;
  2480.         if( m_SaverMode == sm_full )
  2481.         {
  2482.             rcBounds = pMonitorInfo->rcScreen;
  2483.             ScreenToClient( hwnd, (POINT*)&rcBounds.left );
  2484.             ScreenToClient( hwnd, (POINT*)&rcBounds.right );
  2485.         }
  2486.         else
  2487.         {
  2488.             rcBounds = m_rcRenderTotal;
  2489.         }
  2490.  
  2491.         if( pMonitorInfo->widthError == 0 )
  2492.         {
  2493.             if( m_SaverMode == sm_preview )                
  2494.             {
  2495.                 pMonitorInfo->widthError = (float) (rcBounds.right - rcBounds.left);
  2496.                 pMonitorInfo->heightError = (float) (rcBounds.bottom - rcBounds.top);
  2497.                 pMonitorInfo->xError = 0.0f;
  2498.                 pMonitorInfo->yError = 0.0f;
  2499.                 pMonitorInfo->xVelError = 0.0f;
  2500.                 pMonitorInfo->yVelError = 0.0f;
  2501.                 InvalidateRect( hwnd, NULL, FALSE );    // Invalidate the hwnd so it gets drawn
  2502.                 UpdateWindow( hwnd );
  2503.             }
  2504.             else
  2505.             {
  2506.                 pMonitorInfo->widthError = 300;
  2507.                 pMonitorInfo->heightError = 150;
  2508.                 pMonitorInfo->xError = (rcBounds.right + rcBounds.left - pMonitorInfo->widthError) / 2.0f;
  2509.                 pMonitorInfo->yError = (rcBounds.bottom + rcBounds.top - pMonitorInfo->heightError) / 2.0f;
  2510.                 pMonitorInfo->xVelError = (rcBounds.right - rcBounds.left) / 10.0f;
  2511.                 pMonitorInfo->yVelError = (rcBounds.bottom - rcBounds.top) / 20.0f;
  2512.             }
  2513.         }
  2514.         else
  2515.         {
  2516.             if( m_SaverMode != sm_preview )
  2517.             {
  2518.                 RECT rcOld;
  2519.                 RECT rcNew;
  2520.  
  2521.                 SetRect( &rcOld, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
  2522.                     (INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
  2523.                     (INT)(pMonitorInfo->yError + pMonitorInfo->heightError) );
  2524.  
  2525.                 // Update rect velocity
  2526.                 if( (pMonitorInfo->xError + pMonitorInfo->xVelError * fTimeDelta + 
  2527.                     pMonitorInfo->widthError > rcBounds.right && pMonitorInfo->xVelError > 0.0f) ||
  2528.                     (pMonitorInfo->xError + pMonitorInfo->xVelError * fTimeDelta < 
  2529.                     rcBounds.left && pMonitorInfo->xVelError < 0.0f) )
  2530.                 {
  2531.                     pMonitorInfo->xVelError = -pMonitorInfo->xVelError;
  2532.                 }
  2533.                 if( (pMonitorInfo->yError + pMonitorInfo->yVelError * fTimeDelta + 
  2534.                     pMonitorInfo->heightError > rcBounds.bottom && pMonitorInfo->yVelError > 0.0f) ||
  2535.                     (pMonitorInfo->yError + pMonitorInfo->yVelError * fTimeDelta < 
  2536.                     rcBounds.top && pMonitorInfo->yVelError < 0.0f) )
  2537.                 {
  2538.                     pMonitorInfo->yVelError = -pMonitorInfo->yVelError;
  2539.                 }
  2540.                 // Update rect position
  2541.                 pMonitorInfo->xError += pMonitorInfo->xVelError * fTimeDelta;
  2542.                 pMonitorInfo->yError += pMonitorInfo->yVelError * fTimeDelta;
  2543.             
  2544.                 SetRect( &rcNew, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
  2545.                     (INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
  2546.                     (INT)(pMonitorInfo->yError + pMonitorInfo->heightError) );
  2547.  
  2548.                 if( rcOld.left != rcNew.left || rcOld.top != rcNew.top )
  2549.                 {
  2550.                     InvalidateRect( hwnd, &rcOld, FALSE );    // Invalidate old rect so it gets erased
  2551.                     InvalidateRect( hwnd, &rcNew, FALSE );    // Invalidate new rect so it gets drawn
  2552.                     UpdateWindow( hwnd );
  2553.                 }
  2554.             }
  2555.         }
  2556.     }
  2557. }
  2558.  
  2559.  
  2560.  
  2561.  
  2562. //-----------------------------------------------------------------------------
  2563. // Name: GetTextForError()
  2564. // Desc: Translate an HRESULT error code into a string that can be displayed
  2565. //       to explain the error.  A class derived from CD3DScreensaver can 
  2566. //       provide its own version of this function that provides app-specific
  2567. //       error translation instead of or in addition to calling this function.
  2568. //       This function returns TRUE if a specific error was translated, or
  2569. //       FALSE if no specific translation for the HRESULT was found (though
  2570. //       it still puts a generic string into pszError).
  2571. //-----------------------------------------------------------------------------
  2572. BOOL CD3DScreensaver::GetTextForError( HRESULT hr, TCHAR* pszError, 
  2573.                                        DWORD dwNumChars )
  2574. {
  2575.     const DWORD dwErrorMap[][2] = 
  2576.     {
  2577.     //  HRESULT, stringID
  2578.         E_FAIL, IDS_ERR_GENERIC,
  2579.         D3DAPPERR_NODIRECT3D, IDS_ERR_NODIRECT3D,
  2580.         D3DAPPERR_NOWINDOWEDHAL, IDS_ERR_NOWINDOWEDHAL,
  2581.         D3DAPPERR_CREATEDEVICEFAILED, IDS_ERR_CREATEDEVICEFAILED,
  2582.         D3DAPPERR_NOCOMPATIBLEDEVICES, IDS_ERR_NOCOMPATIBLEDEVICES,
  2583.         D3DAPPERR_NOHARDWAREDEVICE, IDS_ERR_NOHARDWAREDEVICE,
  2584.         D3DAPPERR_HALNOTCOMPATIBLE, IDS_ERR_HALNOTCOMPATIBLE,
  2585.         D3DAPPERR_NOHALTHISMODE, IDS_ERR_NOHALTHISMODE,   
  2586.         D3DAPPERR_MEDIANOTFOUND, IDS_ERR_MEDIANOTFOUND,   
  2587.         D3DAPPERR_RESIZEFAILED, IDS_ERR_RESIZEFAILED,    
  2588.         E_OUTOFMEMORY, IDS_ERR_OUTOFMEMORY,     
  2589.         D3DERR_OUTOFVIDEOMEMORY, IDS_ERR_OUTOFVIDEOMEMORY,
  2590.         D3DAPPERR_NOPREVIEW, IDS_ERR_NOPREVIEW
  2591.     };
  2592.     const DWORD dwErrorMapSize = sizeof(dwErrorMap) / sizeof(DWORD[2]);
  2593.  
  2594.     DWORD iError;
  2595.     DWORD resid = 0;
  2596.  
  2597.     for( iError = 0; iError < dwErrorMapSize; iError++ )
  2598.     {
  2599.         if( hr == (HRESULT)dwErrorMap[iError][0] )
  2600.         {
  2601.             resid = dwErrorMap[iError][1];
  2602.         }
  2603.     }
  2604.     if( resid == 0 )
  2605.     {
  2606.         resid = IDS_ERR_GENERIC;
  2607.     }
  2608.  
  2609.     LoadString( NULL, resid, pszError, dwNumChars );
  2610.  
  2611.     if( resid == IDS_ERR_GENERIC )
  2612.         return FALSE;
  2613.     else
  2614.         return TRUE;
  2615. }
  2616.  
  2617.  
  2618.  
  2619.  
  2620. //-----------------------------------------------------------------------------
  2621. // Name: UpdateFrameStats()
  2622. // Desc: Keep track of the frame count
  2623. //-----------------------------------------------------------------------------
  2624. VOID CD3DScreensaver::UpdateFrameStats()
  2625. {
  2626.     UINT iRenderUnit;
  2627.     RenderUnit* pRenderUnit;
  2628.     UINT iAdapter;
  2629.     static FLOAT fLastTime = 0.0f;
  2630.     static DWORD dwFrames  = 0L;
  2631.     FLOAT fTime = DXUtil_Timer( TIMER_GETABSOLUTETIME );
  2632.  
  2633.     ++dwFrames;
  2634.  
  2635.     // Update the scene stats once per second
  2636.     if( fTime - fLastTime > 1.0f )
  2637.     {
  2638.         m_fFPS    = dwFrames / (fTime - fLastTime);
  2639.         fLastTime = fTime;
  2640.         dwFrames  = 0L;
  2641.  
  2642.         for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  2643.         {
  2644.             pRenderUnit = &m_RenderUnits[iRenderUnit];
  2645.             iAdapter = pRenderUnit->iAdapter;
  2646.  
  2647.             // Get adapter's current mode so we can report
  2648.             // bit depth (back buffer depth may be unknown)
  2649.             D3DDISPLAYMODE mode;
  2650.             m_pD3D->GetAdapterDisplayMode( iAdapter, &mode );
  2651.  
  2652.             _stprintf( pRenderUnit->strFrameStats, TEXT("%.02f fps (%dx%dx%d)"), m_fFPS,
  2653.                        mode.Width, mode.Height,
  2654.                        mode.Format==D3DFMT_X8R8G8B8?32:16 );
  2655.             if( m_bUseDepthBuffer )
  2656.             {
  2657.                 D3DAdapterInfo* pAdapterInfo = m_Adapters[iAdapter];
  2658.                 D3DDeviceInfo*  pDeviceInfo  = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
  2659.                 D3DModeInfo*    pModeInfo    = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];
  2660.  
  2661.                 switch( pModeInfo->DepthStencilFormat )
  2662.                 {
  2663.                 case D3DFMT_D16:
  2664.                     lstrcat( pRenderUnit->strFrameStats, TEXT(" (D16)") );
  2665.                     break;
  2666.                 case D3DFMT_D15S1:
  2667.                     lstrcat( pRenderUnit->strFrameStats, TEXT(" (D15S1)") );
  2668.                     break;
  2669.                 case D3DFMT_D24X8:
  2670.                     lstrcat( pRenderUnit->strFrameStats, TEXT(" (D24X8)") );
  2671.                     break;
  2672.                 case D3DFMT_D24S8:
  2673.                     lstrcat( pRenderUnit->strFrameStats, TEXT(" (D24S8)") );
  2674.                     break;
  2675.                 case D3DFMT_D24X4S4:
  2676.                     lstrcat( pRenderUnit->strFrameStats, TEXT(" (D24X4S4)") );
  2677.                     break;
  2678.                 case D3DFMT_D32:
  2679.                     lstrcat( pRenderUnit->strFrameStats, TEXT(" (D32)") );
  2680.                     break;
  2681.                 }
  2682.             }
  2683.         }
  2684.     }
  2685. }
  2686.  
  2687.  
  2688.  
  2689.  
  2690. //-----------------------------------------------------------------------------
  2691. // Name: DoPaint()
  2692. // Desc: 
  2693. //-----------------------------------------------------------------------------
  2694. VOID CD3DScreensaver::DoPaint(HWND hwnd, HDC hdc)
  2695. {
  2696.     HMONITOR hMonitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST );
  2697.     MonitorInfo* pMonitorInfo;
  2698.     for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++)
  2699.     {
  2700.         pMonitorInfo = &m_Monitors[iMonitor];
  2701.         if( pMonitorInfo->hMonitor == hMonitor )
  2702.             break;
  2703.     }
  2704.  
  2705.     if( iMonitor == m_dwNumMonitors )
  2706.         return;
  2707.  
  2708.     // Draw the error message box
  2709.     RECT rc;
  2710.     SetRect( &rc, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
  2711.         (INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
  2712.         (INT)(pMonitorInfo->yError + pMonitorInfo->heightError) );
  2713.     FillRect(hdc, &rc, (HBRUSH)(COLOR_WINDOW+1));
  2714.     FrameRect(hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
  2715.     RECT rc2;
  2716.     int height;
  2717.     rc2 = rc;
  2718.     height = DrawText(hdc, m_szError, -1, &rc, DT_WORDBREAK | DT_CENTER | DT_CALCRECT );
  2719.     rc = rc2;
  2720.  
  2721.     rc2.top = (rc.bottom + rc.top - height) / 2;
  2722.  
  2723.     DrawText(hdc, m_szError, -1, &rc2, DT_WORDBREAK | DT_CENTER );
  2724.  
  2725.     // Erase everywhere except the error message box
  2726.     ExcludeClipRect( hdc, rc.left, rc.top, rc.right, rc.bottom );
  2727.     rc = pMonitorInfo->rcScreen;
  2728.     ScreenToClient( hwnd, (POINT*)&rc.left );
  2729.     ScreenToClient( hwnd, (POINT*)&rc.right );
  2730.     FillRect(hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH) );
  2731. }
  2732.  
  2733.  
  2734.  
  2735.  
  2736. //-----------------------------------------------------------------------------
  2737. // Name: ChangePassword()
  2738. // Desc:
  2739. //-----------------------------------------------------------------------------
  2740. VOID CD3DScreensaver::ChangePassword()
  2741. {
  2742.     // Load the password change DLL
  2743.     HINSTANCE mpr = LoadLibrary( TEXT("MPR.DLL") );
  2744.  
  2745.     if ( mpr != NULL )
  2746.     {
  2747.         // Grab the password change function from it
  2748.         typedef DWORD (PASCAL *PWCHGPROC)( LPCSTR, HWND, DWORD, LPVOID );
  2749.         PWCHGPROC pwd = (PWCHGPROC)GetProcAddress( mpr, "PwdChangePasswordA" );
  2750.  
  2751.         // Do the password change
  2752.         if ( pwd != NULL )
  2753.             pwd( "SCRSAVE", m_hWndParent, 0, NULL );
  2754.  
  2755.         // Free the library
  2756.         FreeLibrary( mpr );
  2757.     }
  2758. }
  2759.  
  2760.  
  2761.  
  2762.  
  2763. //-----------------------------------------------------------------------------
  2764. // Name: DisplayErrorMsg()
  2765. // Desc: Displays error messages in a message box
  2766. //-----------------------------------------------------------------------------
  2767. HRESULT CD3DScreensaver::DisplayErrorMsg( HRESULT hr, DWORD dwType )
  2768. {
  2769.     TCHAR strMsg[512];
  2770.  
  2771.     GetTextForError( hr, strMsg, 512 );
  2772.  
  2773.     MessageBox( m_hWnd, strMsg, m_strWindowTitle, MB_ICONERROR | MB_OK );
  2774.  
  2775.     return hr;
  2776. }
  2777.  
  2778.  
  2779.  
  2780.  
  2781. //-----------------------------------------------------------------------------
  2782. // Name: ReadScreenSettings()
  2783. // Desc: Read the registry settings that affect how the screens are set up and
  2784. //       used.
  2785. //-----------------------------------------------------------------------------
  2786. VOID CD3DScreensaver::ReadScreenSettings( HKEY hkeyParent )
  2787. {
  2788.     TCHAR strKey[100];
  2789.     DWORD iMonitor;
  2790.     MonitorInfo* pMonitorInfo;
  2791.     DWORD iAdapter;
  2792.     D3DAdapterInfo* pD3DAdapterInfo;
  2793.     HKEY hkey;
  2794.     DWORD dwType = REG_DWORD;
  2795.     DWORD dwLength = sizeof(DWORD);
  2796.     DWORD dwLength2 = sizeof(GUID);
  2797.     GUID guidAdapterID;
  2798.     GUID guidZero;
  2799.     ZeroMemory( &guidAdapterID, sizeof(GUID) );
  2800.     ZeroMemory( &guidZero, sizeof(GUID) );
  2801.  
  2802.     RegQueryValueEx( hkeyParent, TEXT("AllScreensSame"), NULL, &dwType, 
  2803.         (BYTE*)&m_bAllScreensSame, &dwLength);
  2804.     for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  2805.     {
  2806.         pMonitorInfo = &m_Monitors[iMonitor];
  2807.         iAdapter = pMonitorInfo->iAdapter;
  2808.         if( iAdapter == NO_ADAPTER )
  2809.             continue; 
  2810.         pD3DAdapterInfo = m_Adapters[iAdapter];
  2811.         wsprintf( strKey, TEXT("Screen %d"), iMonitor + 1 );
  2812.         if( ERROR_SUCCESS == RegCreateKeyEx( hkeyParent, strKey, 
  2813.             0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  2814.         {
  2815.             RegQueryValueEx( hkey, TEXT("Adapter ID"), NULL, &dwType, 
  2816.                 (BYTE*)&guidAdapterID, &dwLength2);
  2817.  
  2818.             RegQueryValueEx( hkey, TEXT("Leave Black"), NULL, &dwType, 
  2819.                 (BYTE*)&pD3DAdapterInfo->bLeaveBlack, &dwLength);
  2820.  
  2821.             if( guidAdapterID == pD3DAdapterInfo->d3dAdapterIdentifier.DeviceIdentifier ||
  2822.                 guidAdapterID == guidZero )
  2823.             {
  2824.                 RegQueryValueEx( hkey, TEXT("Disable Hardware"), NULL, &dwType, 
  2825.                     (BYTE*)&pD3DAdapterInfo->bDisableHW, &dwLength);
  2826.                 RegQueryValueEx( hkey, TEXT("Width"), NULL, &dwType, 
  2827.                     (BYTE*)&pD3DAdapterInfo->dwUserPrefWidth, &dwLength);
  2828.                 RegQueryValueEx( hkey, TEXT("Height"), NULL, &dwType, 
  2829.                     (BYTE*)&pD3DAdapterInfo->dwUserPrefHeight, &dwLength);
  2830.                 RegQueryValueEx( hkey, TEXT("Format"), NULL, &dwType, 
  2831.                     (BYTE*)&pD3DAdapterInfo->d3dfmtUserPrefFormat, &dwLength);
  2832.             }
  2833.             RegCloseKey( hkey);
  2834.         }
  2835.     }
  2836. }
  2837.  
  2838.  
  2839.  
  2840.  
  2841. //-----------------------------------------------------------------------------
  2842. // Name: WriteScreenSettings()
  2843. // Desc: Write the registry settings that affect how the screens are set up and
  2844. //       used.
  2845. //-----------------------------------------------------------------------------
  2846. VOID CD3DScreensaver::WriteScreenSettings( HKEY hkeyParent )
  2847. {
  2848.     TCHAR strKey[100];
  2849.     DWORD iMonitor;
  2850.     MonitorInfo* pMonitorInfo;
  2851.     DWORD iAdapter;
  2852.     D3DAdapterInfo* pD3DAdapterInfo;
  2853.     HKEY hkey;
  2854.  
  2855.     RegSetValueEx( hkeyParent, TEXT("AllScreensSame"), NULL, REG_DWORD, 
  2856.         (BYTE*)&m_bAllScreensSame, sizeof(DWORD) );
  2857.     for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  2858.     {
  2859.         pMonitorInfo = &m_Monitors[iMonitor];
  2860.         iAdapter = pMonitorInfo->iAdapter;
  2861.         if( iAdapter == NO_ADAPTER )
  2862.             continue; 
  2863.         pD3DAdapterInfo = m_Adapters[iAdapter];
  2864.         wsprintf( strKey, TEXT("Screen %d"), iMonitor + 1 );
  2865.         if( ERROR_SUCCESS == RegCreateKeyEx( hkeyParent, strKey, 
  2866.             0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  2867.         {
  2868.             RegSetValueEx( hkey, TEXT("Leave Black"), NULL, REG_DWORD, 
  2869.                 (BYTE*)&pD3DAdapterInfo->bLeaveBlack, sizeof(DWORD) );
  2870.             RegSetValueEx( hkey, TEXT("Disable Hardware"), NULL, REG_DWORD, 
  2871.                 (BYTE*)&pD3DAdapterInfo->bDisableHW, sizeof(DWORD) );
  2872.             RegSetValueEx( hkey, TEXT("Width"), NULL, REG_DWORD, 
  2873.                 (BYTE*)&pD3DAdapterInfo->dwUserPrefWidth, sizeof(DWORD) );
  2874.             RegSetValueEx( hkey, TEXT("Height"), NULL, REG_DWORD, 
  2875.                 (BYTE*)&pD3DAdapterInfo->dwUserPrefHeight, sizeof(DWORD) );
  2876.             RegSetValueEx( hkey, TEXT("Format"), NULL, REG_DWORD, 
  2877.                 (BYTE*)&pD3DAdapterInfo->d3dfmtUserPrefFormat, sizeof(DWORD) );
  2878.             RegSetValueEx( hkey, TEXT("Adapter ID"), NULL, REG_BINARY, 
  2879.                 (BYTE*)&pD3DAdapterInfo->d3dAdapterIdentifier.DeviceIdentifier, sizeof(GUID) );
  2880.             RegCloseKey( hkey);
  2881.         }
  2882.     }
  2883. }
  2884.  
  2885.  
  2886.  
  2887.  
  2888. //-----------------------------------------------------------------------------
  2889. // Name: DoScreenSettingsDialog()
  2890. // Desc: 
  2891. //-----------------------------------------------------------------------------
  2892. VOID CD3DScreensaver::DoScreenSettingsDialog( HWND hwndParent )
  2893. {
  2894.     LPCTSTR pstrTemplate;
  2895.  
  2896.     if( m_dwNumAdapters > 1 && !m_bOneScreenOnly )
  2897.         pstrTemplate = MAKEINTRESOURCE( IDD_MULTIMONITORSETTINGS );
  2898.     else
  2899.         pstrTemplate = MAKEINTRESOURCE( IDD_SINGLEMONITORSETTINGS );
  2900.  
  2901.     DialogBox(m_hInstance, pstrTemplate, hwndParent, ScreenSettingsDlgProcStub );
  2902. }
  2903.  
  2904.  
  2905.  
  2906.  
  2907. //-----------------------------------------------------------------------------
  2908. // Name: ScreenSettingsDlgProcStub()
  2909. // Desc:
  2910. //-----------------------------------------------------------------------------
  2911. INT_PTR CALLBACK CD3DScreensaver::ScreenSettingsDlgProcStub( HWND hWnd, UINT uMsg,
  2912.                                                  WPARAM wParam, LPARAM lParam )
  2913. {
  2914.     return s_pD3DScreensaver->ScreenSettingsDlgProc( hWnd, uMsg, wParam, lParam );
  2915. }
  2916.  
  2917.  
  2918.  
  2919.  
  2920. // We need to store a copy of the original screen settings so that the user
  2921. // can modify those settings in the dialog, then hit Cancel and have the
  2922. // original settings restored.
  2923. static D3DAdapterInfo* s_AdaptersSave[9];
  2924. static BOOL s_bAllScreensSameSave;
  2925.  
  2926. //-----------------------------------------------------------------------------
  2927. // Name: ScreenSettingsDlgProc()
  2928. // Desc:
  2929. //-----------------------------------------------------------------------------
  2930. INT_PTR CD3DScreensaver::ScreenSettingsDlgProc( HWND hWnd, UINT uMsg, 
  2931.                                                 WPARAM wParam, LPARAM lParam )
  2932. {
  2933.     HWND hwndTabs = GetDlgItem(hWnd, IDC_MONITORSTAB);
  2934.     HWND hwndModeList = GetDlgItem(hWnd, IDC_MODESCOMBO);
  2935.     DWORD iMonitor;
  2936.     MonitorInfo* pMonitorInfo;
  2937.     DWORD iAdapter;
  2938.  
  2939.     switch (uMsg)
  2940.     {
  2941.     case WM_INITDIALOG:
  2942.         {
  2943.             INT i = 0;
  2944.             TC_ITEM tie; 
  2945.             TCHAR szFmt[100];
  2946.             TCHAR sz[100];
  2947.  
  2948.             GetWindowText(GetDlgItem(hWnd, IDC_TABNAMEFMT), szFmt, 100);
  2949.  
  2950.             tie.mask = TCIF_TEXT | TCIF_IMAGE; 
  2951.             tie.iImage = -1; 
  2952.             for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  2953.             {
  2954.                 wsprintf(sz, szFmt, iMonitor + 1);
  2955.                 tie.pszText = sz; 
  2956.                 TabCtrl_InsertItem(hwndTabs, i++, &tie);
  2957.             }
  2958.             for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  2959.             {
  2960.                 s_AdaptersSave[iAdapter] = new D3DAdapterInfo;
  2961.                 if( s_AdaptersSave[iAdapter] != NULL )
  2962.                     *s_AdaptersSave[iAdapter] = *m_Adapters[iAdapter];
  2963.             }
  2964.             s_bAllScreensSameSave = m_bAllScreensSame;
  2965.             SetupAdapterPage(hWnd);
  2966.             CheckDlgButton(hWnd, IDC_SAME, (m_bAllScreensSame ? BST_CHECKED : BST_UNCHECKED));
  2967.         }
  2968.         return TRUE;
  2969.  
  2970.     case WM_NOTIFY:
  2971.         {
  2972.             NMHDR* pnmh = (LPNMHDR)lParam;
  2973.             UINT code = pnmh->code;
  2974.             if (code == TCN_SELCHANGE)
  2975.             {
  2976.                 SetupAdapterPage(hWnd);
  2977.             }
  2978.         }
  2979.         return TRUE;
  2980.  
  2981.     case WM_COMMAND:
  2982.         switch( LOWORD( wParam ) )
  2983.         {
  2984.         case IDC_SAME:
  2985.             m_bAllScreensSame = (IsDlgButtonChecked(hWnd, IDC_SAME) == BST_CHECKED);
  2986.             break;
  2987.  
  2988.         case IDC_LEAVEBLACK:
  2989.         case IDC_RENDER:
  2990.             if( m_bOneScreenOnly )
  2991.             {
  2992.                 GetBestAdapter( &iAdapter );
  2993.                 iMonitor = m_Adapters[iAdapter]->iMonitor;
  2994.             }
  2995.             else
  2996.             {
  2997.                 iMonitor = TabCtrl_GetCurSel(hwndTabs);
  2998.             }
  2999.             pMonitorInfo = &m_Monitors[iMonitor];
  3000.             iAdapter = pMonitorInfo->iAdapter;
  3001.             if( IsDlgButtonChecked(hWnd, IDC_LEAVEBLACK) == BST_CHECKED )
  3002.             {
  3003.                 m_Adapters[iAdapter]->bLeaveBlack = TRUE;
  3004.                 EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), FALSE);
  3005.                 EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), FALSE);
  3006.                 EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), FALSE);
  3007.                 EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), FALSE);
  3008.             }
  3009.             else
  3010.             {
  3011.                 m_Adapters[iAdapter]->bLeaveBlack = FALSE;
  3012.                 EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), TRUE);
  3013.                 EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), TRUE);
  3014.                 EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), TRUE);
  3015.                 EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), TRUE);
  3016.             }
  3017.             break;
  3018.  
  3019.         case IDC_MODESCOMBO:
  3020.             if (HIWORD(wParam) == CBN_SELCHANGE)
  3021.             {
  3022.                 DWORD iSel;
  3023.                 DWORD iMode;
  3024.  
  3025.                 if( m_bOneScreenOnly )
  3026.                 {
  3027.                     GetBestAdapter( &iAdapter );
  3028.                     iMonitor = m_Adapters[iAdapter]->iMonitor;
  3029.                 }
  3030.                 else
  3031.                 {
  3032.                     iMonitor = TabCtrl_GetCurSel(hwndTabs);
  3033.                 }
  3034.                 pMonitorInfo = &m_Monitors[iMonitor];
  3035.                 iAdapter = pMonitorInfo->iAdapter;
  3036.                 iSel = ComboBox_GetCurSel( hwndModeList );
  3037.                 if( iSel == 0 )
  3038.                 {
  3039.                     // "Automatic"
  3040.                     m_Adapters[iAdapter]->dwUserPrefWidth = 0;
  3041.                     m_Adapters[iAdapter]->dwUserPrefHeight = 0;
  3042.                     m_Adapters[iAdapter]->d3dfmtUserPrefFormat = D3DFMT_UNKNOWN;
  3043.                 }
  3044.                 else
  3045.                 {
  3046.                     D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
  3047.                     D3DDeviceInfo* pD3DDeviceInfo;
  3048.                     D3DModeInfo* pD3DModeInfo;
  3049.                     pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
  3050.                     iMode = (DWORD)ComboBox_GetItemData( hwndModeList, iSel );
  3051.                     pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  3052.                     m_Adapters[iAdapter]->dwUserPrefWidth = pD3DModeInfo->Width;
  3053.                     m_Adapters[iAdapter]->dwUserPrefHeight = pD3DModeInfo->Height;
  3054.                     m_Adapters[iAdapter]->d3dfmtUserPrefFormat = pD3DModeInfo->Format;
  3055.                 }
  3056.             }
  3057.             break;
  3058.  
  3059.         case IDC_DISABLEHW:
  3060.             if( m_bOneScreenOnly )
  3061.             {
  3062.                 GetBestAdapter( &iAdapter );
  3063.                 iMonitor = m_Adapters[iAdapter]->iMonitor;
  3064.             }
  3065.             else
  3066.             {
  3067.                 iMonitor = TabCtrl_GetCurSel(hwndTabs);
  3068.             }
  3069.             pMonitorInfo = &m_Monitors[iMonitor];
  3070.             iAdapter = pMonitorInfo->iAdapter;
  3071.             if( IsDlgButtonChecked( hWnd, IDC_DISABLEHW ) == BST_CHECKED )
  3072.                 m_Adapters[iAdapter]->bDisableHW = TRUE;
  3073.             else
  3074.                 m_Adapters[iAdapter]->bDisableHW = FALSE;
  3075.             SetupAdapterPage( hWnd );
  3076.             break;
  3077.  
  3078.         case IDC_MOREINFO:
  3079.             {
  3080.                 if( m_bOneScreenOnly )
  3081.                 {
  3082.                     GetBestAdapter( &iAdapter );
  3083.                     iMonitor = m_Adapters[iAdapter]->iMonitor;
  3084.                 }
  3085.                 else
  3086.                 {
  3087.                     iMonitor = TabCtrl_GetCurSel(hwndTabs);
  3088.                 }
  3089.                 pMonitorInfo = &m_Monitors[iMonitor];
  3090.                 iAdapter = pMonitorInfo->iAdapter;
  3091.                 D3DAdapterInfo* pD3DAdapterInfo;
  3092.                 TCHAR szText[500];
  3093.  
  3094.                 if( pMonitorInfo->hMonitor == NULL )
  3095.                     pD3DAdapterInfo = NULL;
  3096.                 else
  3097.                     pD3DAdapterInfo = m_Adapters[pMonitorInfo->iAdapter];
  3098.  
  3099.                 // Accelerated / Unaccelerated settings
  3100.                 BOOL bHasHAL = FALSE;
  3101.                 BOOL bHasAppCompatHAL = FALSE;
  3102.                 BOOL bDisabledHAL = FALSE;
  3103.                 BOOL bHasSW = FALSE;
  3104.                 BOOL bHasAppCompatSW = FALSE;
  3105.     
  3106.                 if( pD3DAdapterInfo != NULL )
  3107.                 {
  3108.                     bHasHAL = pD3DAdapterInfo->bHasHAL;
  3109.                     bHasAppCompatHAL = pD3DAdapterInfo->bHasAppCompatHAL;
  3110.                     bDisabledHAL = pD3DAdapterInfo->bDisableHW;
  3111.                     bHasSW = pD3DAdapterInfo->bHasSW;
  3112.                     bHasAppCompatSW = pD3DAdapterInfo->bHasAppCompatSW;
  3113.                 }
  3114.                 if( bHasHAL && !bDisabledHAL && bHasAppCompatHAL )
  3115.                 {
  3116.                     // Good HAL
  3117.                     LoadString( NULL, IDS_INFO_GOODHAL, szText, 500 );
  3118.                 }
  3119.                 else if( bHasHAL && bDisabledHAL )
  3120.                 {
  3121.                     // Disabled HAL
  3122.                     if( bHasSW && bHasAppCompatSW )
  3123.                         LoadString( NULL, IDS_INFO_DISABLEDHAL_GOODSW, szText, 500 );
  3124.                     else if( bHasSW )
  3125.                         LoadString( NULL, IDS_INFO_DISABLEDHAL_BADSW, szText, 500 );
  3126.                     else 
  3127.                         LoadString( NULL, IDS_INFO_DISABLEDHAL_NOSW, szText, 500 );
  3128.                 }
  3129.                 else if( bHasHAL && !bHasAppCompatHAL )
  3130.                 {
  3131.                     // Bad HAL
  3132.                     if( bHasSW && bHasAppCompatSW )
  3133.                         LoadString( NULL, IDS_INFO_BADHAL_GOODSW, szText, 500 );
  3134.                     else if( bHasSW )
  3135.                         LoadString( NULL, IDS_INFO_BADHAL_BADSW, szText, 500 );
  3136.                     else 
  3137.                         LoadString( NULL, IDS_INFO_BADHAL_NOSW, szText, 500 );
  3138.                 }
  3139.                 else 
  3140.                 {
  3141.                     // No HAL
  3142.                     if( bHasSW && bHasAppCompatSW )
  3143.                         LoadString( NULL, IDS_INFO_NOHAL_GOODSW, szText, 500 );
  3144.                     else if( bHasSW  )
  3145.                         LoadString( NULL, IDS_INFO_NOHAL_BADSW, szText, 500 );
  3146.                     else 
  3147.                         LoadString( NULL, IDS_INFO_NOHAL_NOSW, szText, 500 );
  3148.                 }
  3149.  
  3150.                 MessageBox( hWnd, szText, pMonitorInfo->strDeviceName, MB_OK | MB_ICONINFORMATION );
  3151.                 break;
  3152.             }
  3153.  
  3154.         case IDOK:
  3155.             for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  3156.             {
  3157.                 SAFE_DELETE( s_AdaptersSave[iAdapter] );
  3158.             }
  3159.             EndDialog(hWnd, IDOK);
  3160.             break;
  3161.  
  3162.         case IDCANCEL:
  3163.             // Restore member values to original state
  3164.             for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  3165.             {
  3166.                 if( s_AdaptersSave[iAdapter] != NULL )
  3167.                     *m_Adapters[iAdapter] = *s_AdaptersSave[iAdapter];
  3168.                 SAFE_DELETE( s_AdaptersSave[iAdapter] );
  3169.             }
  3170.             m_bAllScreensSame = s_bAllScreensSameSave;
  3171.             EndDialog(hWnd, IDCANCEL);
  3172.             break;
  3173.         }
  3174.         return TRUE;
  3175.  
  3176.     default:
  3177.         return FALSE;
  3178.     }
  3179. }
  3180.  
  3181.  
  3182.  
  3183.  
  3184. //-----------------------------------------------------------------------------
  3185. // Name: SetupAdapterPage()
  3186. // Desc: Set up the controls for a given page in the Screen Settings dialog.
  3187. //-----------------------------------------------------------------------------
  3188. VOID CD3DScreensaver::SetupAdapterPage( HWND hWnd )
  3189. {
  3190.     HWND hwndTabs = GetDlgItem(hWnd, IDC_MONITORSTAB);
  3191.     HWND hwndModeList = GetDlgItem(hWnd, IDC_MODESCOMBO);
  3192.     UINT iPage = TabCtrl_GetCurFocus(hwndTabs);
  3193.     HWND hwndDesc = GetDlgItem(hWnd, IDC_ADAPTERNAME);
  3194.     MonitorInfo* pMonitorInfo;
  3195.     D3DAdapterInfo* pD3DAdapterInfo;
  3196.     D3DDeviceInfo* pD3DDeviceInfo;
  3197.     D3DModeInfo* pD3DModeInfo;
  3198.  
  3199.     if( m_bOneScreenOnly )
  3200.     {
  3201.         DWORD iAdapter;
  3202.         GetBestAdapter( &iAdapter );
  3203.         if( iAdapter != NO_ADAPTER )
  3204.         {
  3205.             pD3DAdapterInfo = m_Adapters[iAdapter];
  3206.             iPage = pD3DAdapterInfo->iMonitor;
  3207.         }
  3208.     }
  3209.  
  3210.     pMonitorInfo = &m_Monitors[iPage];
  3211.  
  3212.     SetWindowText( hwndDesc, pMonitorInfo->strDeviceName );
  3213.  
  3214.     if( pMonitorInfo->iAdapter == NO_ADAPTER )
  3215.         pD3DAdapterInfo = NULL;
  3216.     else
  3217.         pD3DAdapterInfo = m_Adapters[pMonitorInfo->iAdapter];
  3218.  
  3219.     // Accelerated / Unaccelerated settings
  3220.     BOOL bHasHAL = FALSE;
  3221.     BOOL bHasAppCompatHAL = FALSE;
  3222.     BOOL bDisabledHAL = FALSE;
  3223.     BOOL bHasSW = FALSE;
  3224.     BOOL bHasAppCompatSW = FALSE;
  3225.     
  3226.     if( pD3DAdapterInfo != NULL )
  3227.     {
  3228.         bHasHAL = pD3DAdapterInfo->bHasHAL;
  3229.         bHasAppCompatHAL = pD3DAdapterInfo->bHasAppCompatHAL;
  3230.         bDisabledHAL = pD3DAdapterInfo->bDisableHW;
  3231.         bHasSW = pD3DAdapterInfo->bHasSW;
  3232.         bHasAppCompatSW = pD3DAdapterInfo->bHasAppCompatSW;
  3233.     }
  3234.  
  3235.     TCHAR szStatus[200];
  3236.     if( bHasHAL && !bDisabledHAL && bHasAppCompatHAL )
  3237.     {
  3238.         LoadString( NULL, IDS_RENDERING_HAL, szStatus, 200 );
  3239.     }
  3240.     else if( bHasSW && bHasAppCompatSW )
  3241.     {
  3242.         LoadString( NULL, IDS_RENDERING_SW, szStatus, 200 );
  3243.     }
  3244.     else
  3245.     {
  3246.         LoadString( NULL, IDS_RENDERING_NONE, szStatus, 200 );
  3247.     }
  3248.     SetWindowText( GetDlgItem( hWnd, IDC_RENDERING ), szStatus );
  3249.  
  3250.     if( bHasHAL && bHasAppCompatHAL )
  3251.     {
  3252.         EnableWindow( GetDlgItem( hWnd, IDC_DISABLEHW ), TRUE );
  3253.         CheckDlgButton( hWnd, IDC_DISABLEHW, 
  3254.             pD3DAdapterInfo->bDisableHW ? BST_CHECKED : BST_UNCHECKED );
  3255.     }
  3256.     else
  3257.     {
  3258.         EnableWindow( GetDlgItem( hWnd, IDC_DISABLEHW ), FALSE );
  3259.         CheckDlgButton( hWnd, IDC_DISABLEHW, BST_UNCHECKED );
  3260.     }
  3261.  
  3262.     if( ( bHasAppCompatHAL && !bDisabledHAL ) || bHasAppCompatSW )
  3263.     {
  3264.         if( pD3DAdapterInfo->bLeaveBlack )
  3265.             CheckRadioButton(hWnd, IDC_RENDER, IDC_LEAVEBLACK, IDC_LEAVEBLACK);
  3266.         else
  3267.             CheckRadioButton(hWnd, IDC_RENDER, IDC_LEAVEBLACK, IDC_RENDER);
  3268.         EnableWindow(GetDlgItem(hWnd, IDC_LEAVEBLACK), TRUE);
  3269.         EnableWindow(GetDlgItem(hWnd, IDC_RENDER), TRUE);
  3270.         EnableWindow(GetDlgItem(hWnd, IDC_SCREENUSAGEBOX), TRUE);
  3271.  
  3272.     }
  3273.     else
  3274.     {
  3275.         CheckRadioButton(hWnd, IDC_RENDER, IDC_LEAVEBLACK, IDC_LEAVEBLACK);
  3276.         EnableWindow(GetDlgItem(hWnd, IDC_LEAVEBLACK), FALSE);
  3277.         EnableWindow(GetDlgItem(hWnd, IDC_RENDER), FALSE);
  3278.         EnableWindow(GetDlgItem(hWnd, IDC_SCREENUSAGEBOX), FALSE);
  3279.     }
  3280.  
  3281.     if( IsDlgButtonChecked(hWnd, IDC_LEAVEBLACK) == BST_CHECKED )
  3282.     {
  3283.         EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), FALSE);
  3284.         EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), FALSE);
  3285.         EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), FALSE);
  3286.         EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), FALSE);
  3287.     }
  3288.     else
  3289.     {
  3290.         EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), TRUE);
  3291.         EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), TRUE);
  3292.         EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), TRUE);
  3293.         EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), TRUE);
  3294.     }
  3295.  
  3296.     // Mode list
  3297.     ComboBox_ResetContent( hwndModeList );
  3298.     if( pD3DAdapterInfo == NULL )
  3299.         return;
  3300.     TCHAR strAutomatic[100];
  3301.     GetWindowText(GetDlgItem(hWnd, IDC_AUTOMATIC), strAutomatic, 100);
  3302.     ComboBox_AddString( hwndModeList, strAutomatic );
  3303.     ComboBox_SetItemData( hwndModeList, 0, -1 );
  3304.     pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
  3305.     DWORD iSelInitial = 0;
  3306.     TCHAR strModeFmt[100];
  3307.  
  3308.     GetWindowText(GetDlgItem(hWnd, IDC_MODEFMT), strModeFmt, 100);
  3309.     for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++ )
  3310.     {
  3311.         DWORD dwBitDepth;
  3312.         TCHAR strMode[80];
  3313.         DWORD dwItem;
  3314.  
  3315.         pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  3316.         dwBitDepth = 16;
  3317.         if( pD3DModeInfo->Format == D3DFMT_X8R8G8B8 ||
  3318.             pD3DModeInfo->Format == D3DFMT_A8R8G8B8 ||
  3319.             pD3DModeInfo->Format == D3DFMT_R8G8B8 )
  3320.         {
  3321.             dwBitDepth = 32;
  3322.         }
  3323.  
  3324.         wsprintf( strMode, strModeFmt, pD3DModeInfo->Width,
  3325.                   pD3DModeInfo->Height, dwBitDepth );
  3326.         dwItem = ComboBox_AddString( hwndModeList, strMode );
  3327.         ComboBox_SetItemData( hwndModeList, dwItem, iMode );
  3328.  
  3329.         if( pD3DModeInfo->Width == pD3DAdapterInfo->dwUserPrefWidth &&
  3330.             pD3DModeInfo->Height == pD3DAdapterInfo->dwUserPrefHeight &&
  3331.             pD3DModeInfo->Format == pD3DAdapterInfo->d3dfmtUserPrefFormat )
  3332.         {
  3333.             iSelInitial = dwItem;
  3334.         }
  3335.     }
  3336.     ComboBox_SetCurSel( hwndModeList, iSelInitial );
  3337. }
  3338.